package com.yanqu.road.logic.activity.hotpotjump.game;

import com.yanqu.road.entity.autodata.hotpotjump.*;
import com.yanqu.road.entity.autodata.hotpotjump.config.*;
import com.yanqu.road.entity.log.hotpotjump.LogHotpotJumpJumpMove;
import com.yanqu.road.logic.activity.hotpotjump.HotpotJumpConfig;
import com.yanqu.road.logic.activity.hotpotjump.game.choose.HotpotJumpSkillChoose;
import com.yanqu.road.logic.pb.HotpotJumpPb;
import com.yanqu.road.pb.activity.HotpotJumpProto;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.classutil.ClassHelper;
import com.yanqu.road.utils.config.Config;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

public class HotpotJumpGameLogic {
    private static Logger logger = LogManager.getLogger(HotpotJumpGameLogic.class.getName());
    public static final HotpotJumpBoard board = new HotpotJumpBoard();
    static Map<String, Class<?>> classMap = new HashMap<>();

    static {
        try {
            Package gamePackage = HotpotJumpGameLogic.class.getPackage();
            Set<Class<?>> classes = ClassHelper.getClasses(gamePackage);
            for (Class<?> aClass : classes) {
                classMap.put(aClass.getSimpleName(), aClass);
            }
        } catch (Exception e) {

        }
    }

    public RandomHelper randomHelper = new RandomHelper();
    private HotpotJumpConfig config;
    private UserHotpotJumpGameData gameData;
    private Map<Integer, HotpotJumpUnit> unitMap = new HashMap<>();//游戏单位索引
    private Map<JumpBoardGrid, HotpotJumpGrid> effectGridMap = new HashMap<>(); //特效格子索引

    private List<JumpBoardGrid> jumpGrids = new ArrayList<>();//落点
    private List<List<JumpBoardGrid>> allJumpPathGrids = new ArrayList<>();//跳跃路径
    private List<JumpBoardGrid> allMoveGrids = new ArrayList<>();
    private Set<JumpBoardGrid> polygonGridSet = new HashSet<>();//多边形的交叉点,有交叉必定有多边形
    private int lastPolygonIdx = -1;
    private List<JumpBoardGrid> pathUnitGrids = new ArrayList<>(); //路径上的敌方单位所在坐标
    private Map<JumpBoardGrid, Set<eJumpDirection>> gridDirectionMap = new HashMap<>();//每个格子连接的方向
    private Map<HotpotJumpUnit, Integer> actionNumMap = new HashMap<>(); //单位已行动数
    private Map<JumpBoardGrid, List<Integer>> unitWaitDealSkillMap = new HashMap<>();// 单位等待结算的主角技能

    private Map<HotpotJumpUnit, Set<HotpotJumpGrid>> unitAtkMainRoleRecordMap = new HashMap<>(); //单位进攻主角的记录

    private int totalDamage;
    private int totalBeHurt;
    private int totalScoreAdd = 0;
    private int totalExpAdd;
    private List<Integer> killIds = new ArrayList<>();

    private List<List<HotpotJumpShowGridChange>> showList = new ArrayList<>();
    private int showAmount = 1;
    private boolean isBuySilver = false;
    private boolean isBuyGold = false;
    private boolean isGuide = false;
    private boolean isOnlyCheckUnitAtk = false; //只用来检查主角位移后,哪些怪能打到主角

    public HotpotJumpGameLogic(HotpotJumpConfig config, UserHotpotJumpGameData userGameData) {
        this.config = config;
        if (userGameData != null && userGameData.getMainRole() != null) {
            this.gameData = userGameData.clone();
            for (HotpotJumpUnit unit : gameData.getUnits()) {
                joinUnit(unit, false);

                for (List<Integer> effect : unit.getHeadPos().getEffects()) {
                    int skillId = effect.get(0);
                    HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                    if (skillConfig == null) {
                        continue;
                    }
                    if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Freeze.getValue()) {
                        actionNumMap.put(unit, 999);
                        break;
                    }
                }
            }

            for (HotpotJumpGrid effectGrid : gameData.getEffectGrids()) {
                JumpBoardGrid boardGrid = findBoardGridByJumpGrid(effectGrid);
                effectGridMap.put(boardGrid, effectGrid);
            }
        }
    }

    public void joinUnit(HotpotJumpUnit unit, boolean isNew) {
        unitMap.put(unit.getHeadPos().calcPostKey(), unit);
        for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
            unitMap.put(bodyPo.calcPostKey(), unit);
        }

        if (isNew) {
            //Boss会覆盖普通小兵,要重新赋值盘面单位
            gameData.getUnits().add(unit);

            HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.NewUnit);
            show.setUnit(unit);
        }
    }

    public HotpotJumpShowGridChange createShow(eHotpotJumpShow type) {
        HotpotJumpShowGridChange show = new HotpotJumpShowGridChange(type.getValue());
        if (showAmount > showList.size()) {
            showList.add(new ArrayList<>());
        }
        showList.get(showList.size() - 1).add(show);
        return show;
    }

    public HotpotJumpConfig getConfig() {
        return config;
    }

    public Map<Integer, HotpotJumpUnit> getUnitMap() {
        return unitMap;
    }

    public List<JumpBoardGrid> getJumpGrids() {
        return jumpGrids;
    }

    public List<List<JumpBoardGrid>> getAllJumpPathGrids() {
        return allJumpPathGrids;
    }

    public List<JumpBoardGrid> getAllMoveGrids() {
        return allMoveGrids;
    }

    public Set<JumpBoardGrid> getPolygonGridSet() {
        return polygonGridSet;
    }

    public int getLastPolygonIdx() {
        return lastPolygonIdx;
    }

    public List<JumpBoardGrid> getPathUnitGrids() {
        return pathUnitGrids;
    }

    public Map<JumpBoardGrid, Set<eJumpDirection>> getGridDirectionMap() {
        return gridDirectionMap;
    }

    public List<List<HotpotJumpShowGridChange>> getShowList() {
        return showList;
    }

    public <T> T getHotpotJumpInterfaceInstance(String className) throws IllegalAccessException, InstantiationException {
        Class<?> aClass = classMap.get(className);
        return (T) aClass.newInstance();
    }

    public HotpotJumpSkillChoose getSkillChooseInstance(HotpotJumpSkillConfig skillConfig, int skillLv) {
        if (skillConfig == null) {
            return null;
        }
        try {
            HotpotJumpSkillChoose skillChoose = getHotpotJumpInterfaceInstance("HotpotJumpSkillChoose" + skillConfig.getChooseType());
            return skillChoose.init(skillConfig, skillLv, this);
        } catch (Exception e) {
            logger.error("技能配置错误 {}={} err:{}", skillConfig.getId(), skillConfig.getChooseType(), e);
        }
        return null;
    }

    public UserHotpotJumpGameData getGameData() {
        return gameData;
    }

    public UserHotpotJumpGameData initGame() {
        this.gameData = new UserHotpotJumpGameData();
        gameData.setRound(1);
        gameData.setScore(0);
        gameData.setMaxUnitId(1);
        gameData.setPotId(config.randomPotId());
        gameData.setMainRole(config.initMainRole());
        //初始小怪
        for (HotpotJumpUnit unit : config.initEnemyList(this)) {
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }
        //随机一个BOSS的出现顺序
        gameData.setBossIds(config.randomBossSort());

        HotpotJumpMissionConfig missionConfig = config.getFirstMissionConfig();
        if (missionConfig != null) {
            gameData.setUnitPoolId(1);
            gameData.setUnitPoolRemain(config.getUnionPool(missionConfig));
        }

        createNewUnitsByRandomMatch(config.getExtraEnemyNum());

        return gameData;
    }

    public HotpotJumpUnit findUnitByGrid(JumpBoardGrid grid) {
        return unitMap.get(grid.getPosKey());
    }

    public JumpBoardGrid findBoardGridByJumpGrid(HotpotJumpGrid jumpGrid) {
        return board.findGrid(jumpGrid.getX(), jumpGrid.getY());
    }

    public void stepChange(eHotpotJumpStep step) {
        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.StepChange);
        show.setStep(step.getValue());
        gameData.setGameStep(step.getValue());
    }

    public int jumpByGuide(List<HotpotJumpProto.HotpotJumpGridTemp> posList) {
        this.isGuide = true;
        return jump(posList, false, false);
    }

    /**
     * 检查威胁用,怪不掉血的
     *
     * @param posList
     * @return
     */
    public int jumpByOnlyCheckUnitAtk(List<HotpotJumpProto.HotpotJumpGridTemp> posList) {
        this.isOnlyCheckUnitAtk = true;
        return jump(posList, false, false);
    }

    public int jump(List<HotpotJumpProto.HotpotJumpGridTemp> posList, boolean isBuySilver, boolean isBuyGold) {
        this.isBuySilver = isBuySilver;
        this.isBuyGold = isBuyGold;

        if (posList.isEmpty()) {
            return 1;
        }
        JumpBoardGrid startGrid = findBoardGridByJumpGrid(gameData.getMainRole().getGrid());
        if (startGrid == null) {
            return 2;//盘面上找不到主角的点
        }

        this.allMoveGrids.add(startGrid);
        boolean isJump = true;
        Map<JumpBoardGrid, Set<eJumpDirection>> tempGridDirectionMap = new HashMap<>();//每个格子连接的方向
        JumpBoardGrid iterGrid = startGrid;
        for (int i = 0; i < posList.size(); i++) {
            HotpotJumpProto.HotpotJumpGridTemp pos = posList.get(i);
            JumpBoardGrid jumpGrid = board.findGrid(pos.getX(), pos.getY());
            if (jumpGrid == null) {
                return 3;//路径点不在盘面上
            }
            jumpGrids.add(jumpGrid);
            if (iterGrid.equals(jumpGrid)) {
                return 4;
            }
            if (iterGrid.calcTargetDirection(jumpGrid) == eJumpDirection.None) {//不在一个直线上
                return 5;
            }

            List<JumpBoardGrid> tempPathGrids = board.findPathGridsBetweenTowGrids(iterGrid, jumpGrid);
            if (tempPathGrids.size() == 2) {//走一步的只能一个路径
                if (posList.size() > 1) {
                    return 7;
                }
                isJump = false;
            }

            for (List<JumpBoardGrid> pathGrid : this.allJumpPathGrids) {
                if ((pathGrid.get(0) == iterGrid && pathGrid.get(pathGrid.size() - 1) == jumpGrid)
                        || (pathGrid.get(0) == jumpGrid && pathGrid.get(pathGrid.size() - 1) == iterGrid)) {
                    return 9;//重复路径
                }
            }

            //遍历一下,作为障碍点必须离跳跃的两个点距离一样
            JumpBoardGrid findUnitGrid = null;
            for (int j = 0; j < tempPathGrids.size(); j++) {
                JumpBoardGrid tempPathGrid = tempPathGrids.get(j);
                HotpotJumpUnit unitByGrid = findUnitByGrid(tempPathGrid);
                if (unitByGrid != null) {
                    //判断一下是不是特殊BOSS3,只要离中间点的距离一样就能跳
                    if (config.isBoss3(unitByGrid.getConfigId())) {
                        JumpBoardGrid headGrid = findBoardGridByJumpGrid(unitByGrid.getHeadPos());
                        if (iterGrid.distanceTo(headGrid) != jumpGrid.distanceTo(headGrid)) {
                            return 7;
                        }
                        findUnitGrid = headGrid;
                    } else {
                        if (iterGrid.distanceTo(tempPathGrid) != jumpGrid.distanceTo(tempPathGrid)) {
                            return 8;
                        }
                        findUnitGrid = tempPathGrid;
                    }
                }

                eJumpDirection fromDirection = tempPathGrid.calcTargetDirection(iterGrid);
                if (fromDirection != eJumpDirection.None) {
                    Set<eJumpDirection> directionSet = tempGridDirectionMap.get(tempPathGrid);
                    if (directionSet == null) {
                        directionSet = new HashSet<>();
                        tempGridDirectionMap.put(tempPathGrid, directionSet);
                    }
                    directionSet.add(fromDirection);
                }

                eJumpDirection toDirection = tempPathGrid.calcTargetDirection(jumpGrid);
                if (toDirection != eJumpDirection.None) {
                    Set<eJumpDirection> directionSet = tempGridDirectionMap.get(tempPathGrid);
                    if (directionSet == null) {
                        directionSet = new HashSet<>();
                        tempGridDirectionMap.put(tempPathGrid, directionSet);
                    }
                    directionSet.add(toDirection);
                }

                if (j > 0) {
                    int nowAllMoveIdx = this.allMoveGrids.size();
                    if (this.allMoveGrids.contains(tempPathGrid)) {
                        this.polygonGridSet.add(tempPathGrid);
                        lastPolygonIdx = nowAllMoveIdx;
                    }
                    this.allMoveGrids.add(tempPathGrid);
                }
            }

            if (findUnitGrid != null) {
                this.pathUnitGrids.add(findUnitGrid);
            }

            if (findUnitGrid == null && isJump) {
                return 9;
            }

            this.allJumpPathGrids.add(tempPathGrids);//缓存路径

            //更新主角位置
            mainRoleMove(jumpGrid);
            if (isJump) {
                onJumpSkillDeal();
            }
            showAmount++;


            iterGrid = jumpGrid;
        }

        gridDirectionMap = tempGridDirectionMap;

        if (isJump) {
            gameData.setJumpAmount(this.pathUnitGrids.size());
            jumpAtk(startGrid);
            afterJumpSkillDeal();
        } else {
            stationaryAtk();
        }

        dealMainRoleTriggerTrap();

        unitBeHurtSkillSettle();

        if (gameData.getJumpAmount() >= (isBuySilver ? config.getSilverCombSkillNeed() : config.getCombSkillNeed())) {
            combSkillDeal();
            unitBeHurtSkillSettle();
        }

        showAmount++;

        stepChange(eHotpotJumpStep.JumpEnd);
        //结算一下怪的死亡,加经验,升级,如果升级要先处理技能才能到怪物行动
        unitDeadSettle();

//        printfBoard();

        if (!gameData.getSkillIds().isEmpty()) {//等待技能选择
            return 0;
        }

        //怪开始动
        unitAction();
        unitDeadSettle();
        if (isMainRoleDead()) {//主角死了,等复活
            return 0;
        }

        if (!gameData.getSkillIds().isEmpty()) {//等待技能选择
            return 0;
        }
        //最终结算,进入下一回合,还是失败或者通关
        roundEnd();
        return 0;
    }

    /**
     * 处理主角触发的陷阱,以及陷阱结算
     */
    private void dealMainRoleTriggerTrap() {
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        HotpotJumpGrid effectGrid = effectGridMap.get(mainRoleBordGrid);
        if (effectGrid != null) {
            for (List<Integer> effect : effectGrid.getEffects()) {
                int skillId = effect.get(0);
                int effectValue = effect.get(2);
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig == null) {
                    continue;
                }
                if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss2Skill.getValue()) {//更新踩到的DeBuff回合
                    int roundContinue = skillConfig.skillEffect.getValueByLevel(1, 4);
                    gameData.getMainRole().getGrid().addEffect(skillId, roundContinue, effectValue);
                    HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
                    show.setMainRole(gameData.getMainRole());
                    show.setSkillId(skillId);
                }
            }
        }

        boolean haveOldBuff = false;
        //结算DeBuff
        for (List<Integer> effect : gameData.getMainRole().getGrid().getEffects()) {
            int skillId = effect.get(0);
            HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
            if (skillConfig == null) {
                continue;
            }
            if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss2Skill.getValue()) {
                haveOldBuff = true;
                int hurtValue = effect.get(2);
                HotpotJumpShowGridChange show = unitHurtMainRole(null, hurtValue, effectGrid);
                show.setSkillId(skillId);
            }
        }
        //效果回合减1
        gameData.getMainRole().getGrid().effectDecOneRound();
        if (haveOldBuff && gameData.getMainRole().getGrid().getEffects().isEmpty()) {
            HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
            show.setMainRole(gameData.getMainRole());
        }
    }

    /**
     * 连击技能处理
     */
    private void combSkillDeal() {
        HotpotJumpModelConfig config = this.config.getModelConfigByType(eHotpotJumpUnit.MainRole.getValue());
        dealMainRoleSkill(Integer.parseInt(config.getSpecialSkill()), isBuySilver ? 2 : 1, eHotpotSkillTrigger.Combo);
    }

    /**
     * 主角移动
     *
     * @param grid
     */
    public void mainRoleMove(JumpBoardGrid grid) {
        gameData.getMainRole().getGrid().setX(grid.getX());
        gameData.getMainRole().getGrid().setY(grid.getY());
        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.Move);
        show.setMainRole(gameData.getMainRole());
    }

    /**
     * 主角技能处理
     *
     * @param skillId
     * @param skillLv
     * @param trigger
     */
    private void dealMainRoleSkill(int skillId, int skillLv, eHotpotSkillTrigger trigger) {
        if (isOnlyCheckUnitAtk) {
            return;
        }
        HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }

        if (skillConfig.getTriggerTiming() != trigger.getValue()) {
            return;
        }

        HotpotJumpSkillChoose skillChoose = getSkillChooseInstance(skillConfig, skillLv);
        if (skillChoose == null) {
            return;
        }

        dealChooseGridDamageEffect(skillId, skillChoose.chooseGrid(), skillConfig.skillEffect, skillLv);
    }

    public HotpotJumpGrid gridAddNewEffect(JumpBoardGrid grid, int skillId, int round, int value) {
        HotpotJumpGrid hotpotJumpGrid = effectGridMap.get(grid);
        if (hotpotJumpGrid == null) {
            hotpotJumpGrid = new HotpotJumpGrid(grid.getX(), grid.getY());
            effectGridMap.put(grid, hotpotJumpGrid);
            gameData.getEffectGrids().add(hotpotJumpGrid);
        }

        hotpotJumpGrid.addEffect(skillId, round, value);
        return hotpotJumpGrid;
    }

    /**
     * 处理主角的技能效果
     *
     * @param grids
     * @param skillEffect
     */
    private void dealChooseGridDamageEffect(int skillId, List<List<JumpBoardGrid>> grids, HotpotJumpSkillEffect skillEffect, int skillLv) {
        if (grids.isEmpty()) {
            return;
        }
        if (skillEffect.getEffectType() != eHotpotJumpEffect.Damage.getValue()
                && skillEffect.getEffectType() != eHotpotJumpEffect.GridTrapDamage.getValue()
                && skillEffect.getEffectType() != eHotpotJumpEffect.Freeze.getValue()) {
            return;
        }
        for (List<JumpBoardGrid> gridList : grids) {
            //先给格子加表现
            List<HotpotJumpGrid> showGrids = new ArrayList<>();
            for (JumpBoardGrid grid : gridList) {
                HotpotJumpUnit findUnit = findUnitByGrid(grid);
                if (findUnit != null ) {
                    if (skillEffect.getEffectType() == eHotpotJumpEffect.Freeze.getValue()) {
                        if (!config.isBoss(findUnit.getConfigId())) {
                            int rate = skillEffect.getValueByLevel(skillLv);
                            if (randomHelper.next(1000) < rate) {
                                int maxActionNum = config.getModelConfigById(findUnit.getConfigId()).getActionNum();
                                actionNumMap.put(findUnit, maxActionNum);
                                findUnit.getHeadPos().addEffect(skillId, 1, 0);
                                HotpotJumpShowGridChange freezeShow = createShow(eHotpotJumpShow.EffectChange);
                                freezeShow.setSkillId(skillId);
                                freezeShow.setUnit(findUnit);
                            }
                        }
                    } else {
                        List<Integer> list = unitWaitDealSkillMap.get(grid);
                        if (list == null) {
                            list = new ArrayList<>();
                            unitWaitDealSkillMap.put(grid, list);
                        }
                        list.add(skillId);
                    }
                }

                if (skillEffect.getEffectType() == eHotpotJumpEffect.GridTrapDamage.getValue()) {//陷阱持续1回合
                    HotpotJumpGrid hotpotJumpGrid = gridAddNewEffect(grid, skillId, 1, 0);
                    showGrids.add(hotpotJumpGrid.clone());
                } else {
                    HotpotJumpGrid jumpGrid = new HotpotJumpGrid(grid.getX(), grid.getY());
                    showGrids.add(jumpGrid);
                }
            }
            if (skillEffect.getEffectType() != eHotpotJumpEffect.Freeze.getValue()) {
                HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
                show.setGrids(showGrids);
                show.setSkillId(skillId);
            }

//            //然后再计算伤害
//            for (JumpBoardGrid findUnitGrid : findUnitGrids) {
//
//                if (skillEffect.getEffectType() == eHotpotJumpEffect.Damage.getValue()) {
//                    if (findUnitGrid != null) {
//                        int skillValue = skillEffect.getValueByLevel(skillLv);
//                        int damage = gameData.getMainRole().calcSkillDamage(skillValue, getRoleSkillAddAtkMulti());
//                        onceAtkUnit(findUnitGrid, damage, false, true);
//                    }
//                } else if (skillEffect.getEffectType() == eHotpotJumpEffect.Freeze.getValue()) {
//                    HotpotJumpUnit unit = findUnitByGrid(findUnitGrid);
//                    if (!config.isBoss(unit.getConfigId())) {
//                        int rate = skillEffect.getValueByLevel(skillLv);
//                        if (randomHelper.next(1000) < rate) {
//                            int maxActionNum = config.getModelConfigById(unit.getConfigId()).getActionNum();
//                            actionNumMap.put(unit, maxActionNum);
//                            HotpotJumpShowGridChange freezeShow = createShow(eHotpotJumpShow.EffectChange);
//                            freezeShow.setSkillId(skillId);
//                            freezeShow.setUnit(unit);
//                        }
//                    }
//                }
//            }
        }
    }

    /**
     * 结算单位被攻击的技能效果
     */
    private void unitBeHurtSkillSettle() {
        HotpotJumpModelConfig roleModelConfig = this.config.getModelConfigByType(eHotpotJumpUnit.MainRole.getValue());
        int combSkillId = Integer.parseInt(roleModelConfig.getSpecialSkill());
        for (Map.Entry<JumpBoardGrid, List<Integer>> entry : unitWaitDealSkillMap.entrySet()) {
            JumpBoardGrid findUnitGrid = entry.getKey();
            List<Integer> skillList = entry.getValue();
            for (Integer skillId : skillList) {
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig == null) {
                    continue;
                }
                int skillLv = 1;
                if (combSkillId == skillId) {
                    skillLv = isBuySilver ? 2 : 1;
                } else {
                    skillLv = gameData.getMainRole().findSkillLv(skillId);
                }
                HotpotJumpSkillEffect skillEffect = skillConfig.skillEffect;

                if (skillEffect.getEffectType() == eHotpotJumpEffect.Damage.getValue()) {
                    int skillValue = skillEffect.getValueByLevel(skillLv);
                    int damage = gameData.getMainRole().calcSkillDamage(skillValue, getRoleSkillAddAtkMulti(), config.getJumpAtkMulti(gameData.getJumpAmount()));
                    HotpotJumpShowGridChange atkShow = onceAtkUnit(findUnitGrid, damage, false, true);
                    if (atkShow != null) {
                        atkShow.setSkillId(skillId);
                    }
                }
            }
        }
        unitWaitDealSkillMap.clear();
    }

    /**
     * 跳跃前的技能处理
     */
    private void roundEndSkillDeal() {
        for (List<Integer> skill : gameData.getMainRole().getSkills()) {
            int skillId = skill.get(0);
            int skillLv = skill.get(1);
            dealMainRoleSkill(skillId, skillLv, eHotpotSkillTrigger.RoundEnd);
        }
    }

    /**
     * 跳跃中的技能处理
     */
    private void onJumpSkillDeal() {
        for (List<Integer> skill : gameData.getMainRole().getSkills()) {
            int skillId = skill.get(0);
            int skillLv = skill.get(1);
            dealMainRoleSkill(skillId, skillLv, eHotpotSkillTrigger.OnJump);
        }
    }

    /**
     * 主角技能需要判定是否加攻击千分比的技能值
     *
     * @return
     */
    private int getRoleSkillAddAtkMulti() {
        int addAtkMulti = 0;
        for (List<Integer> skill : gameData.getMainRole().getSkills()) {
            int skillId = skill.get(0);
            int skillLv = skill.get(1);
            HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
            if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.LifeLessAddAtk.getValue()) {
                int hpRemainRateNeed = skillConfig.skillEffect.getValueByLevel(skillLv, 2);
                int hp = gameData.getMainRole().getGrid().getHp();
                int hpMax = gameData.getMainRole().getGrid().getHpMax();
                int hpRemainRate = (int) (hp * 1000 / hpMax);
                if (hpRemainRate <= hpRemainRateNeed) {
                    addAtkMulti += skillConfig.skillEffect.getValueByLevel(skillLv);
                }
            }
        }
        return addAtkMulti;
    }

    /**
     * 原地攻击,打周围一圈的怪
     */
    private void stationaryAtk() {
        if (isOnlyCheckUnitAtk) {
            return;
        }
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        int damage = gameData.getMainRole().calcStationaryDamage(config.getMoveAtkMulti(), getRoleSkillAddAtkMulti());

        List<JumpBoardGrid> surroundGrids = board.findSurroundGrids(mainRoleBordGrid, 1);
        for (JumpBoardGrid surroundGrid : surroundGrids) {
            onceAtkUnit(surroundGrid, damage, false, false);
        }

    }

    /**
     * 跳跃攻击
     */
    private void jumpAtk(JumpBoardGrid startGrid) {
        if (isOnlyCheckUnitAtk) {
            return;
        }
        for (int i = 0; i < pathUnitGrids.size(); i++) {
            JumpBoardGrid pathUnitGrid = pathUnitGrids.get(i);
            List<JumpBoardGrid> pathGrids = this.allJumpPathGrids.get(i);
            int damage = gameData.getMainRole().calcJumpDamage(pathGrids.size() - 1, getRoleSkillAddAtkMulti(), config.getJumpAtkMulti(gameData.getJumpAmount()));
            onceAtkUnit(pathUnitGrid, damage, true, true);
        }
    }

    /**
     * 跳跃后的技能处理
     */
    private void afterJumpSkillDeal() {
        for (List<Integer> skill : gameData.getMainRole().getSkills()) {
            int skillId = skill.get(0);
            int skillLv = skill.get(1);
            dealMainRoleSkill(skillId, skillLv, eHotpotSkillTrigger.AfterJump);
        }
    }

    /**
     * 主角对敌方单位单次伤害结算
     *
     * @param grid
     * @param damage
     */
    private HotpotJumpShowGridChange onceAtkUnit(JumpBoardGrid grid, int damage, boolean canBloodSucking, boolean canCritical) {
        HotpotJumpUnit unit = findUnitByGrid(grid);
        if (unit == null) {
            return null;
        }

//        if (unit.isDead()) {
//            return null;
//        }

        int realDamage = damage;
        boolean triggerCri = false;
        if (canCritical) {
            realDamage = gameData.getMainRole().calcTriggerCriDamage(randomHelper, damage); //是否暴击
            triggerCri = realDamage > damage;
        }

        int canSuckDamage = realDamage;

        HotpotJumpGrid findUnitGrid = null;
        boolean haveShield = false;
        if (config.isBoss4(unit.getConfigId())) {//boss4要所有护盾打掉才能扣血
            for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                if (bodyPo.getShield() > 0) {
                    haveShield = true;
                    break;
                }
            }
            findUnitGrid = unit.findGridByAll(grid.getX(), grid.getY());
            if (!haveShield) {
                findUnitGrid = unit.getHeadPos();
            }
        } else {
            findUnitGrid = unit.getHeadPos();
        }

        if (findUnitGrid == null) {
            return null;
        }

        boolean needDizzy = false;
        if (findUnitGrid.getShield() > 0) {//抵扣一次伤害
            findUnitGrid.setShield(findUnitGrid.getShield() - 1);

            realDamage = 0;
            canSuckDamage = 0;
            if (config.isBoss4(unit.getConfigId())) {//boss4护盾全掉的时候,进入眩晕,无法攻击无法释放技能
                needDizzy = true;
                if (unit.getHeadPos().getShield() > 0) {
                    needDizzy = false;
                } else {
                    for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                        if (bodyPo.getShield() > 0) {
                            needDizzy = false;
                            break;
                        }
                    }
                }
            } else {
                needDizzy = false;
            }
        } else if (!haveShield) {//要都没有护盾才能扣血
            if (findUnitGrid.getHp() <= 0) {
                canSuckDamage = 0;
            } else {
                if (canSuckDamage > findUnitGrid.getHp()) {
                    canSuckDamage = findUnitGrid.getHp();
                }
            }

            findUnitGrid.setHp(findUnitGrid.getHp() - realDamage);
        }

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.BeHurt);
        show.setUnit(unit);
        show.setCri(triggerCri);

        if (canBloodSucking) {
            int suckValue = gameData.getMainRole().calcBloodSucking(canSuckDamage);
            if (suckValue > 0) {
                gameData.getMainRole().getGrid().setHp(gameData.getMainRole().getGrid().getHp() + suckValue);
                if (gameData.getMainRole().getGrid().getHp() > gameData.getMainRole().getGrid().getHpMax()) {
                    gameData.getMainRole().getGrid().setHp(gameData.getMainRole().getGrid().getHpMax());
                }
                HotpotJumpShowGridChange suckShow = createShow(eHotpotJumpShow.BloodSucking);
                suckShow.setMainRole(gameData.getMainRole());
                suckShow.setUnit(unit);
            }
        }

        if (needDizzy) {
            HotpotJumpModelConfig modelConfigById = config.getModelConfigById(unit.getConfigId());
            List<Integer> list = StringUtils.stringToIntegerList(modelConfigById.getSpecialSkill(), "\\|");
            for (Integer skillId : list) {
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss4Dizzy.getValue()) {
                    int continueRound = skillConfig.skillEffect.getValueByLevel(1);
                    int nextSkill = skillConfig.skillEffect.getValueByLevel(1, 2);
                    unit.getHeadPos().addEffect(skillId, continueRound, nextSkill);
                    HotpotJumpShowGridChange dizzyShow = createShow(eHotpotJumpShow.EffectChange);
                    dizzyShow.setUnit(unit);
                    dizzyShow.setSkillId(skillId);
                }
            }
        }

        this.totalDamage += realDamage;
        return show;
    }

    private void unitDeadSettle() {
        List<HotpotJumpUnit> needRemove = new ArrayList<>();
        int baseScoreAdd = 0;
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            if (unit.isDead()) {
                if (!config.isBoss(unit.getConfigId())) {
                    mainRoleAddExp(unit.getExp());
                } else {//Boss加当前总经验千分比的经验值
                    HotpotJumpLevelConfig levelConfig = config.getMainRoleLevelConfig(gameData.getMainRole().getLv());
                    int expAdd = (levelConfig.getExp() * config.getBossExpAdd() + 1) / 1000;
                    mainRoleAddExp(expAdd);

                    if (config.isBoss2(unit.getConfigId())) {//墨鱼死亡,要把这个怪放的陷阱清除
                        removeEffectGridByEffectType(eHotpotJumpEffect.Boss2Skill.getValue());
                    }
                }

                needRemove.add(unit);
                int scoreAdd = config.getModelScore(unit.getConfigId());
                baseScoreAdd += scoreAdd;

                killIds.add(unit.getConfigId());
            }
        }

        if (baseScoreAdd > 0) {
            int resultScore = 0;
            if (isBuyGold) {
                resultScore = BigDecimal.valueOf(baseScoreAdd)
                        .multiply(BigDecimal.valueOf(1000 + config.getTokenScoreMulti()).divide(BigDecimal.valueOf(1000)))
                        .multiply(BigDecimal.valueOf(config.getJumpScoreMulti(gameData.getJumpAmount())).divide(BigDecimal.valueOf(1000)))
                        .setScale(0, RoundingMode.UP).intValue();
            } else {
                resultScore = BigDecimal.valueOf(baseScoreAdd)
                        .multiply(BigDecimal.valueOf(config.getJumpScoreMulti(gameData.getJumpAmount())).divide(BigDecimal.valueOf(1000)))
                        .setScale(0, RoundingMode.UP).intValue();
            }


            addGameScore(baseScoreAdd, resultScore);
        }


        for (HotpotJumpUnit unit : needRemove) {
            removeUnitMap(unit);
            gameData.getUnits().remove(unit);
        }

        mainRoleLvUpCheck();
    }

    public void addGameScore(int baseScoreAdd, int resultScore) {
        if (resultScore == 0) {
            return;
        }
        gameData.setScore(gameData.getScore() + resultScore);
        this.totalScoreAdd += resultScore;

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.ScoreAdd);
        List<Integer> values = new ArrayList<>();
        values.add(baseScoreAdd);
        values.add(resultScore);
        show.setValues(values);
    }

    public void mainRoleLvUpCheck() {
        int newLevel = config.calcMainRoleLevel(gameData.getMainRole().getExp());
        if (newLevel > gameData.getMainRole().getLv()) {
            //升级随机技能
            gameData.getMainRole().setLv(gameData.getMainRole().getLv() + 1);
            reCalcMainRoleAttr();
            List<Integer> skillIds = config.randomMainRoleSkill(gameData.getMainRole().getSkills(), isGuide, gameData.getMainRole().calcRemainHpRate());
            gameData.setSkillIds(skillIds);
        }
    }

    public void mainRoleAddExp(int exp) {
        gameData.getMainRole().setExp(gameData.getMainRole().getExp() + exp);
        this.totalExpAdd += exp;
    }

    /**
     * 敌方单位开始行动
     */
    public void unitAction() {
        stepChange(eHotpotJumpStep.UnitAction);
        //先按和主角的距离排序
        JumpBoardGrid mainRoleGrid = getMainRoleBordGrid();
        List<HotpotJumpUnit> sortUnits = new ArrayList<>(gameData.getUnits());
        sortUnits.sort((o1, o2) -> {
            JumpBoardGrid o1Grid = findBoardGridByJumpGrid(o1.getHeadPos());
            JumpBoardGrid o2Grid = findBoardGridByJumpGrid(o2.getHeadPos());
            int distance1 = mainRoleGrid.distanceTo(o1Grid);
            int distance2 = mainRoleGrid.distanceTo(o2Grid);
            return Integer.compare(distance1, distance2);
        });


//        printfBoard();
        for (int i = 0; i < 10; i++) {
            //全部走一步
            boolean isAllStop = true;
            List<HotpotJumpUnit> waitRemovePosUnits = new ArrayList<>();//移动后才移除旧的位置
            List<HotpotJumpUnit> bossUnits = new ArrayList<>();
            for (HotpotJumpUnit unit : sortUnits) {
                if (i == 0) {
                    dealUnitTriggerTrap(unit);//最开始算一下陷阱
                }

                HotpotJumpUnit cloneUnit = unit.clone();
                if (!config.isBoss(unit.getConfigId())) {
                    if (normalUnitMove(unit)) {
                        isAllStop = false;

                        if (unit.getHeadPos().getX() != cloneUnit.getHeadPos().getX() || unit.getHeadPos().getY() != cloneUnit.getHeadPos().getY()) {
                            waitRemovePosUnits.add(cloneUnit);
                        }
                    }
                } else {
                    bossUnits.add(unit);
                }
            }

            for (HotpotJumpUnit cloneUnit : waitRemovePosUnits) {
                removeUnitMap(cloneUnit);
            }

            //boss最后动
            for (HotpotJumpUnit bossUnit : bossUnits) {
                if (isUnitDizzy(bossUnit)) {
                    continue;
                }
                if (bossUnit.isDead()) {
                    continue;
                }
                if (bossUnitMove(bossUnit)) {
                    isAllStop = false;
                }
            }

//            if (!isAllStop) {// 测试代码
//                printfBoard();
//            }

            if (isAllStop) {
                break;
            }
        }

        //全部走完再判断一次进攻
        sortUnits.sort((o1, o2) -> {
            JumpBoardGrid o1Grid = findBoardGridByJumpGrid(o1.getHeadPos());
            JumpBoardGrid o2Grid = findBoardGridByJumpGrid(o2.getHeadPos());
            int distance1 = mainRoleGrid.distanceTo(o1Grid);
            int distance2 = mainRoleGrid.distanceTo(o2Grid);
            return Integer.compare(distance1, distance2);
        });
        for (HotpotJumpUnit unit : sortUnits) {
            if (isUnitDizzy(unit)) {
                continue;
            }
            if (unit.isDead()) {
                continue;
            }
            if (!config.isBoss(unit.getConfigId())) {//boss没有普工,只有技能
                unitNormalAtk(unit);
            } else {
                dealBossUnitSkill(unit);
            }

            if (isMainRoleDead()) {
                break;
            }
        }
    }

    /**
     * 单位是否眩晕
     *
     * @return
     */
    private boolean isUnitDizzy(HotpotJumpUnit unit) {
        for (List<Integer> effect : unit.getHeadPos().getEffects()) {
            int skillId = effect.get(0);

            HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
            if (skillConfig == null) {
                continue;
            }

            if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss4Dizzy.getValue()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 执行单位的技能效果
     *
     * @param unit
     */
    private void dealBossUnitSkill(HotpotJumpUnit unit) {
        HotpotJumpModelConfig modelConfig = config.getModelConfigMap().get(unit.getConfigId());
        if (modelConfig == null) {
            return;
        }
        unitSkillSettle(unit, modelConfig.getNormalSkill());
        List<Integer> skills = StringUtils.stringToIntegerList(modelConfig.getSpecialSkill(), "\\|");
        for (Integer skill : skills) {
            unitSkillSettle(unit, skill);
        }
    }

    private void unitSkillSettle(HotpotJumpUnit bossUnit, int skillId) {
        HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        int skillValue = skillConfig.skillEffect.getValueByLevel(1);

        int hurtValue = gameData.getMainRole().calcHurtValue(bossUnit, config.isBoss(bossUnit.getConfigId()), skillValue);
        JumpBoardGrid headBoardGrid = findBoardGridByJumpGrid(bossUnit.getHeadPos());
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Damage.getValue()) {
            HotpotJumpSkillRange skillRange = config.findSkillRange(skillConfig, 1);
            {
                List<JumpBoardGrid> grids = calcRangeGrids(headBoardGrid, skillRange, null);
                if (grids.contains(mainRoleBordGrid)) {//主角在技能范围内,释放boss技能
                    HotpotJumpShowGridChange show = unitHurtMainRole(bossUnit, hurtValue, bossUnit.getHeadPos());
                    show.setSkillId(skillId);
                }
            }

            int bodyNeedCheck = skillConfig.skillEffect.getValueByLevel(1, 2);
            if (bodyNeedCheck == 1) {//boss2墨鱼和boss3,身体也要单独判定一次
                for (HotpotJumpGrid bodyPo : bossUnit.getBodyPos()) {
                    JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                    List<JumpBoardGrid> grids = calcRangeGrids(bodyBoardGrid, skillRange, null);
                    if (grids.contains(mainRoleBordGrid)) {//主角在技能范围内,释放boss技能
                        HotpotJumpShowGridChange show = unitHurtMainRole(bossUnit, hurtValue, bodyPo);
                        show.setSkillId(skillId);
                    }
                }
            }
        } else if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss1Skill.getValue()) {
            //使用身体进行技能判定
            HotpotJumpSkillRange skillRange = config.findSkillRange(skillConfig, 1);
            for (int i = 0; i < bossUnit.getBodyPos().size(); i++) {
                HotpotJumpGrid bodyJumpGrid = bossUnit.getBodyPos().get(i);
                JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyJumpGrid);
                List<JumpBoardGrid> grids = calcRangeGrids(bodyBoardGrid, skillRange, null);

                if (!grids.contains(mainRoleBordGrid)) {//主角在技能范围内,释放boss技能
                    continue;
                }
                HotpotJumpShowGridChange show = unitHurtMainRole(bossUnit, hurtValue, bodyJumpGrid);
                show.setSkillId(skillId);
            }
        } else if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss2Skill.getValue()) {
            //检查回合能不能放
            //伤害=每x回合启动=陷阱存在回合时长=陷阱伤害回合
            int roundNeed = skillConfig.skillEffect.getValueByLevel(1, 2);
            int roundContinue = skillConfig.skillEffect.getValueByLevel(1, 3);
            int roundPass = gameData.getRound() - bossUnit.getCreateRound();
            if (roundPass == 1 || (roundPass > 0 && roundPass % roundNeed == 0)) {
                if (roundPass != 1) {
                    //原地留墨汁
                    List<HotpotJumpGrid> showGrids = new ArrayList<>();
                    showGrids.add(gridAddNewEffect(headBoardGrid, skillId, roundContinue + 1, hurtValue).clone());

                    for (HotpotJumpGrid bodyPo : bossUnit.getBodyPos()) {
                        JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                        showGrids.add(gridAddNewEffect(bodyBoardGrid, skillId, roundContinue + 1, hurtValue).clone());
                    }

                    HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
                    show.setGrids(showGrids);
                    show.setSkillId(skillId);
                }

                {
                    dealUnitTriggerTrap(bossUnit);//位移之前算一下陷阱
                    //随机变更位置
                    removeUnitMap(bossUnit);
                    List<JumpBoardGrid> emptyGrids = findEmptyGrids(0);
                    List<JumpBoardGrid> emptyGrids1 = new ArrayList<>();
                    for (JumpBoardGrid emptyGrid : emptyGrids) {
                        if (effectGridMap.containsKey(emptyGrid)) {//不能出现在墨子上
                            continue;
                        }
                        emptyGrids1.add(emptyGrid);
                    }
                    Collections.shuffle(emptyGrids1);
                    int emptyIdx = 0;
                    if (emptyIdx < emptyGrids1.size()) {
                        bossUnit.getHeadPos().setX(emptyGrids1.get(emptyIdx).getX());
                        bossUnit.getHeadPos().setY(emptyGrids1.get(emptyIdx).getY());
                    }
                    for (HotpotJumpGrid bodyPo : bossUnit.getBodyPos()) {
                        emptyIdx++;
                        if (emptyIdx < emptyGrids1.size()) {
                            bodyPo.setX(emptyGrids1.get(emptyIdx).getX());
                            bodyPo.setY(emptyGrids1.get(emptyIdx).getY());
                        }
                    }
                    joinUnit(bossUnit, false);


                    HotpotJumpShowGridChange show2 = createShow(eHotpotJumpShow.Move);
                    show2.setUnit(bossUnit);
                    show2.setSkillId(skillId);

                    dealUnitTriggerTrap(bossUnit);//位移之后算一下陷阱
                }
            }
        } else if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss4Skill.getValue()) {
            List<JumpBoardGrid> neighbors = board.getNeighbors(headBoardGrid);
            List<JumpBoardGrid> surroundGrids = board.findSurroundGrids(headBoardGrid, 2);
            surroundGrids.removeAll(neighbors);//最外围一圈的格子

            boolean atkMainRole = false;
            for (JumpBoardGrid surroundGrid : surroundGrids) {//干掉最外围一圈格子的怪
                HotpotJumpUnit unitByGrid = findUnitByGrid(surroundGrid);
                if (unitByGrid == bossUnit) {
                    continue;
                }

                if (unitByGrid != null) {
                    killUnitByBoss(unitByGrid);
                }

                if (surroundGrid == mainRoleBordGrid) {
                    atkMainRole = true;
                }
            }
            if (atkMainRole) {
                int atkTimes = skillConfig.skillEffect.getValueByLevel(1, 2);
                hurtValue = atkTimes * hurtValue;
                HotpotJumpShowGridChange show = unitHurtMainRole(bossUnit, hurtValue, null);
                show.setSkillId(skillId);
            }
        } else if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Shield.getValue()) {//boss的护盾是加层
            int roundNeed = skillConfig.skillEffect.getValueByLevel(1, 2);
            int roundPass = gameData.getRound() - bossUnit.getCreateRound();
            if (roundPass > 0 && roundPass % roundNeed == 0) {
                bossUnit.getHeadPos().setShield(1);
                if (config.isBoss4(bossUnit.getConfigId())) {
                    for (HotpotJumpGrid bodyPo : bossUnit.getBodyPos()) {
                        bodyPo.setShield(1);
                    }
                }
                HotpotJumpShowGridChange show2 = createShow(eHotpotJumpShow.EffectChange);
                show2.setUnit(bossUnit);
                show2.setSkillId(skillId);
            }
        }
    }

    public void killUnitByBoss(HotpotJumpUnit unit) {
        unit.getHeadPos().setHp(0);
        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.KillByBoss);
        show.setUnit(unit);
        removeUnitMap(unit);
        gameData.getUnits().remove(unit);
    }

    public void killUnitByBossBody(HotpotJumpUnit bossUnit) {
        JumpBoardGrid headBoardGrid = findBoardGridByJumpGrid(bossUnit.getHeadPos());
        HotpotJumpUnit unitByGrid = findUnitByGrid(headBoardGrid);
        if (unitByGrid != null && unitByGrid != bossUnit) {
            killUnitByBoss(unitByGrid);
        }
        for (HotpotJumpGrid bodyPo : bossUnit.getBodyPos()) {
            JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
            unitByGrid = findUnitByGrid(bodyBoardGrid);
            if (unitByGrid == null || unitByGrid == bossUnit) {
                continue;
            }
            killUnitByBoss(unitByGrid);
        }
    }


    private boolean isMainRoleDead() {
        return gameData.getMainRole().getGrid().getHp() <= 0;
    }

    public JumpBoardGrid getMainRoleBordGrid() {
        JumpBoardGrid mainRoleGrid = findBoardGridByJumpGrid(gameData.getMainRole().getGrid());
        return mainRoleGrid;
    }

    /**
     * 单位开始移动
     *
     * @param unit
     */
    private boolean normalUnitMove(HotpotJumpUnit unit) {
        if (unit.isDead()) {
            return false;
        }

        if (canAtkMainRole(unit)) {
            return false;
        }
        int actionNum = actionNumMap.getOrDefault(unit, 0);
        int maxActionNum = config.getModelConfigById(unit.getConfigId()).getActionNum();
        int remainActionNum = maxActionNum - actionNum;
        if (remainActionNum <= 0) {
            return false;
        }
        actionNum++;
        actionNumMap.put(unit, actionNum);

        JumpBoardGrid mainRoleGrid = getMainRoleBordGrid();
        JumpBoardGrid nextGrid = null;
        JumpBoardGrid headBoardGrid = findBoardGridByJumpGrid(unit.getHeadPos());
        JumpBoardGrid startGrid = headBoardGrid;
        nextGrid = calcMoveNextGrid(startGrid, mainRoleGrid);

        if (nextGrid == null) {
            return false;
        }

//        removeUnitMap(unit);

        unit.getHeadPos().setX(nextGrid.getX());
        unit.getHeadPos().setY(nextGrid.getY());
        joinUnit(unit, false);

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.Move);
        show.setUnit(unit);

        dealUnitTriggerTrap(unit);//走之后算一下陷阱
        return true;
    }

    private boolean bossUnitMove(HotpotJumpUnit unit) {
        int actionNum = actionNumMap.getOrDefault(unit, 0);
        int maxActionNum = config.getModelConfigById(unit.getConfigId()).getActionNum();
        int remainActionNum = maxActionNum - actionNum;
        if (remainActionNum <= 0) {
            return false;
        }
        actionNum++;
        actionNumMap.put(unit, actionNum);

        JumpBoardGrid mainRoleGrid = getMainRoleBordGrid();
        JumpBoardGrid nextGrid = null;
        JumpBoardGrid headBoardGrid = findBoardGridByJumpGrid(unit.getHeadPos());
        JumpBoardGrid startGrid = headBoardGrid;
        int headDistance = headBoardGrid.distanceTo(mainRoleGrid);
        if (config.isBoss4(unit.getConfigId())) {//Boss4肥牛卷用离主角最近的身体来进行移动判定
            if (headDistance == 2) {//头部距离主角为2,最优移动,不走了
                return false;
            }

            int minDistance = 99999;
            for (eJumpDirection direction : eJumpDirection.getAllValidDirections()) {//顺时针判断一圈
                boolean canMove = true;
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                    List<Integer> pos = bodyBoardGrid.findDirectionNeighborPos(direction);
                    int x = pos.get(0);
                    int y = pos.get(1);
                    JumpBoardGrid bodyNextGrid = board.findGrid(x, y);
                    if (bodyNextGrid == null || bodyNextGrid == mainRoleGrid) {
                        canMove = false;
                        break;
                    }
                }

                if (canMove) {
                    List<Integer> headNextPos = headBoardGrid.findDirectionNeighborPos(direction);
                    JumpBoardGrid headNextGrid = board.findGrid(headNextPos.get(0), headNextPos.get(1));
                    if (headNextGrid == null || headNextGrid == mainRoleGrid) {
                        break;
                    }
                    int distance = headNextGrid.distanceTo(mainRoleGrid);//头部距离玩家为2是最优移动方向
                    if (distance == 2) {
                        nextGrid = headNextGrid;
                        minDistance = distance;
                        break;
                    }
                    if (distance < minDistance) {
                        minDistance = distance;
                        nextGrid = headNextGrid;
                    }
                }
            }

            if (remainActionNum == 1 && minDistance > 2) {//行动数剩1,判定要继续移动还是,移动后距离还没到2,不走了,身体顺时针走一格
                nextGrid = null;
                int distanceNeed = 2;
                boolean canMove = true;
                Map<HotpotJumpGrid, JumpBoardGrid> bodyNextBoardGridMap = new HashMap<>();
                JumpBoardGrid iterateGrid = headBoardGrid;//循环起始点,右上终点
                for (int i = 0; i < distanceNeed; i++) {
                    List<Integer> pos = iterateGrid.findDirectionNeighborPos(eJumpDirection.RightUp);
                    int x = pos.get(0);
                    int y = pos.get(1);
                    JumpBoardGrid rightUpGrid = board.findGrid(x, y);
                    if (rightUpGrid == null) {
                        rightUpGrid = new JumpBoardGrid(x, y);
                    }
                    iterateGrid = rightUpGrid;
                }
                List<eJumpDirection> clockwiseDirections = eJumpDirection.RightUp.getClockwiseDirections();
                for (eJumpDirection direction : clockwiseDirections) {
                    for (int i = 0; i < distanceNeed; i++) {
                        List<Integer> pos = iterateGrid.findDirectionNeighborPos(direction);
                        int x = pos.get(0);
                        int y = pos.get(1);
                        JumpBoardGrid nextclockwiseGrid = board.findGrid(x, y);
                        if (nextclockwiseGrid == null) {
                            canMove = false;
                            break;
                        }
                        HotpotJumpGrid bodyJumpGrid = unit.findGridByAll(iterateGrid.getX(), iterateGrid.getY());
                        if (bodyJumpGrid != null) {
                            bodyNextBoardGridMap.put(bodyJumpGrid, nextclockwiseGrid);
                        }
                        iterateGrid = nextclockwiseGrid;
                    }
                    if (!canMove) {
                        break;
                    }
                }

                if (canMove) {
                    for (Map.Entry<HotpotJumpGrid, JumpBoardGrid> entry : bodyNextBoardGridMap.entrySet()) {
                        HotpotJumpGrid bodyJumpGrid = entry.getKey();
                        JumpBoardGrid bodyNextGrid = entry.getValue();
                        bodyJumpGrid.setX(bodyNextGrid.getX());
                        bodyJumpGrid.setY(bodyNextGrid.getY());
                    }

                    HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.Move);
                    show.setUnit(unit);
                    killUnitByBossBody(unit);//击杀可能存在的其他单位
                    //更新索引
                    removeUnitMap(unit);
                    joinUnit(unit, false);
                }
            }
        } else if (config.isBoss3(unit.getConfigId())) {
            if (headDistance == 2) {//头部距离主角为2,最优移动,不走了
                return false;
            }
            int minDistance = 99999;
            for (eJumpDirection direction : eJumpDirection.getAllValidDirections()) {//顺时针判断一圈
                boolean canMove = true;
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                    List<Integer> pos = bodyBoardGrid.findDirectionNeighborPos(direction);
                    int x = pos.get(0);
                    int y = pos.get(1);
                    JumpBoardGrid bodyNextGrid = board.findGrid(x, y);
                    if (bodyNextGrid == null || bodyNextGrid == mainRoleGrid) {
                        canMove = false;
                    }
                }

                if (canMove) {
                    List<Integer> pos = headBoardGrid.findDirectionNeighborPos(direction);
                    int x = pos.get(0);
                    int y = pos.get(1);
                    JumpBoardGrid boardGrid = board.findGrid(x, y);
                    int distance = boardGrid.distanceTo(mainRoleGrid);//头部距离玩家最近是最优移动方向
                    if (distance < minDistance) {
                        minDistance = distance;
                        nextGrid = boardGrid;
                    }
                }
            }
        } else if (config.isBoss1(unit.getConfigId())) {//boss1,头和身体都离主角为1就不动了
            if (headDistance == 1) {
                boolean isAllBodyDistance1 = true;
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                    if (bodyBoardGrid.distanceTo(mainRoleGrid) != 1) {
                        isAllBodyDistance1 = false;
                        break;
                    }
                }
                if (isAllBodyDistance1) {
                    return false;
                }
            }

            //找头部周围的空格
            int minDistance = 99999;
            for (eJumpDirection direction : eJumpDirection.getAllValidDirections()) {//顺时针判断一圈
                List<Integer> pos = headBoardGrid.findDirectionNeighborPos(direction);
                int x = pos.get(0);
                int y = pos.get(1);
                JumpBoardGrid neighborGrid = board.findGrid(x, y);
                if (neighborGrid == null) {
                    continue;
                }

                if (neighborGrid == mainRoleGrid) {
                    continue;
                }

                HotpotJumpUnit unitByGrid = findUnitByGrid(neighborGrid);
                if (unitByGrid != null) {
                    continue;
                }

                if (neighborGrid.distanceTo(mainRoleGrid) != 1) {
                    List<JumpBoardGrid> neighborNeighbors = board.getNeighbors(neighborGrid);
                    int neighborNeighborEmptyNum = 0;
                    for (JumpBoardGrid neighborNeighbor : neighborNeighbors) {
                        HotpotJumpUnit unitByGrid1 = findUnitByGrid(neighborNeighbor);
                        if (unitByGrid1 != null) {
                            continue;
                        }
                        neighborNeighborEmptyNum++;
                    }

                    if (neighborNeighborEmptyNum < 2) {
                        continue;
                    }
                }

                int distance = neighborGrid.distanceTo(mainRoleGrid);//头部距离玩家最近是最优移动方向
                if (distance < minDistance) {
                    minDistance = distance;
                    nextGrid = neighborGrid;
                }
            }
        } else {
            nextGrid = calcMoveNextGrid(startGrid, mainRoleGrid);
        }

        if (nextGrid == null) {
            return false;
        }

        if (config.isBoss1(unit.getConfigId())) {//BOSS1先移动头部,身体依次往前
            //线性身体倒叙
            for (int i = unit.getBodyPos().size() - 1; i >= 1; i--) {
                HotpotJumpGrid bodyGrid = unit.getBodyPos().get(i);
                HotpotJumpGrid beforeGrid = unit.getBodyPos().get(i - 1);
                bodyGrid.setX(beforeGrid.getX());
                bodyGrid.setY(beforeGrid.getY());
            }
            HotpotJumpGrid firstBodyGrid = unit.getBodyPos().get(0);
            firstBodyGrid.setX(unit.getHeadPos().getX());
            firstBodyGrid.setY(unit.getHeadPos().getY());

            unit.getHeadPos().setX(nextGrid.getX());
            unit.getHeadPos().setY(nextGrid.getY());
        } else if (config.isBoss4(unit.getConfigId()) || config.isBoss3(unit.getConfigId())) {
            eJumpDirection direction = headBoardGrid.calcTargetDirection(nextGrid);
            unit.getHeadPos().setX(nextGrid.getX());
            unit.getHeadPos().setY(nextGrid.getY());
            //所有身体都往指定方向移动
            for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                List<Integer> pos = bodyBoardGrid.findDirectionNeighborPos(direction);
                int x = pos.get(0);
                int y = pos.get(1);
                bodyPo.setX(x);
                bodyPo.setY(y);
            }
        } else {//小兵直接改位置
            unit.getHeadPos().setX(nextGrid.getX());
            unit.getHeadPos().setY(nextGrid.getY());
        }

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.Move);
        show.setUnit(unit);

        killUnitByBossBody(unit);//击杀可能存在的其他单位
        joinUnit(unit, false);

        dealUnitTriggerTrap(unit);//走之后算一下陷阱
        return true;
    }

    private void removeUnitMap(HotpotJumpUnit unit) {
        unitMap.remove(unit.getHeadPos().calcPostKey());
        for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
            unitMap.remove(bodyPo.calcPostKey());
        }
    }

    /**
     * 根据移动权重移动
     * ①每次移动前计算怪物可移动单元格的移动权重
     * 可移动单元=相邻单元-被其他怪物占领单元
     * ②定义怪物单元格为Mm，怪物相邻的某单元格为Nn，主角单元格在Qq
     * 移动权重=|N-Q|+|n-q|+0.5*|M-N|
     * ③怪物优先往权重最低的单元格移动
     * ④若某怪物某次移动中可移动单元为空，则不移动
     * ④除特殊机制外，若某怪物与主角相邻，则不移动
     *
     * @param startGrid
     * @param endGrid
     * @return
     */
    public JumpBoardGrid calcMoveNextGrid(JumpBoardGrid startGrid, JumpBoardGrid endGrid) {
        int distance = startGrid.distanceTo(endGrid);
//        if (distance <= 1) {
//            return null;
//        }

        JumpBoardGrid findGrid = null;
        List<JumpBoardGrid> neighbors = board.getNeighbors(startGrid);
        BigDecimal minWeight = BigDecimal.valueOf(999999);
        for (JumpBoardGrid neighbor : neighbors) {
            HotpotJumpUnit unitByGrid = findUnitByGrid(neighbor);
            if (unitByGrid != null) {
                continue;
            }
            if (neighbor == endGrid) {
                continue;
            }
            if (distance == 1) {//已经在主角旁边了,不能离开主角
                int neighborDistance = neighbor.distanceTo(endGrid);
                if (neighborDistance > 1) {
                    continue;
                }
            }

            int value1 = Math.abs(neighbor.getX() - endGrid.getX()) + Math.abs(neighbor.getY() - endGrid.getY());
            int value2 = Math.abs(startGrid.getX() - neighbor.getX());
            BigDecimal weight = BigDecimal.valueOf(value1).add(BigDecimal.valueOf(value2).divide(BigDecimal.valueOf(2)));

//            int value1 = Math.abs(neighbor.getQ() - endGrid.getQ()) + Math.abs(neighbor.getR() - endGrid.getR());
//            int value2 = Math.abs(startGrid.getQ() - neighbor.getQ());
//            BigDecimal weight = BigDecimal.valueOf(value1).add(BigDecimal.valueOf(value2).divide(BigDecimal.valueOf(2)));

            if (weight.compareTo(minWeight) < 0) {
                minWeight = weight;
                findGrid = neighbor;
            }
        }

        return findGrid;
    }

    public int findNeighborMinDistance(JumpBoardGrid grid, JumpBoardGrid endGrid, Set<JumpBoardGrid> excludeGrids) {
        int minDistance = 999;
        for (JumpBoardGrid neighbor : board.getNeighbors(grid)) {
            HotpotJumpUnit unitByGrid = findUnitByGrid(neighbor);
            if (unitByGrid != null) {
                continue;
            }
            if (excludeGrids.contains(neighbor)) {
                continue;
            }
            int distance = grid.distanceTo(endGrid);
            if (distance < minDistance) {
                minDistance = distance;
            }
        }
        return minDistance;
    }

    private HotpotJumpShowGridChange unitHurtMainRole(HotpotJumpUnit unit, int hurtValue, HotpotJumpGrid jumpGrid) {
        //先减护盾
        if (hurtValue > gameData.getMainRole().getGrid().getShield()) {
            gameData.getMainRole().getGrid().setShield(0);
            gameData.getMainRole().getGrid().setHp(gameData.getMainRole().getGrid().getHp() - (hurtValue - gameData.getMainRole().getGrid().getShield()));

            this.totalBeHurt += (hurtValue - gameData.getMainRole().getGrid().getShield());
        } else {
            gameData.getMainRole().getGrid().setShield(gameData.getMainRole().getGrid().getShield() - hurtValue);
        }

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.AtkMainRole);
        if (unit != null) {
            show.setUnit(unit);
        }
        if (jumpGrid != null) {
            show.getGrids().add(jumpGrid.clone());
        }
        show.setMainRole(gameData.getMainRole());

        //算一下反击,反击只反头部
        if (!isMainRoleDead() && unit != null) {
            int hurtReflect = gameData.getMainRole().calcHurtReflect(hurtValue);
            if (hurtReflect > 0) {
                JumpBoardGrid headGrid = findBoardGridByJumpGrid(unit.getHeadPos());
                HotpotJumpShowGridChange reflectShow = onceAtkUnit(headGrid, hurtReflect, false, false);
                if (reflectShow != null) {
                    reflectShow.setShowType(eHotpotJumpShow.HurtReflect.getValue());
                }
            }
        }

        //记录一下
        if (unit != null) {
            Set<HotpotJumpGrid> hotpotJumpGridSet = unitAtkMainRoleRecordMap.get(unit);
            if (hotpotJumpGridSet == null) {
                hotpotJumpGridSet = new HashSet<>();
                unitAtkMainRoleRecordMap.put(unit, hotpotJumpGridSet);
            }
            if (jumpGrid != null) {
                hotpotJumpGridSet.add(jumpGrid);
            } else {
                hotpotJumpGridSet.add(unit.getHeadPos());
            }
        }

        return show;
    }

    /**
     * 敌方单位进攻主角
     *
     * @param unit
     */
    private void unitNormalAtk(HotpotJumpUnit unit) {
        int actionNum = actionNumMap.getOrDefault(unit, 0);
        HotpotJumpModelConfig modelConfigById = config.getModelConfigById(unit.getConfigId());
        int maxActionNum = modelConfigById.getActionNum();
        if (actionNum >= maxActionNum) {
            return;
        }

        if (canAtkMainRole(unit)) {
            actionNumMap.put(unit, maxActionNum);//攻击后就不能行动了,把行动数填满

            int hurtValue = gameData.getMainRole().calcHurtValue(unit, false, 1000);
            unitHurtMainRole(unit, hurtValue, null);
        }
    }

    private boolean canAtkMainRole(HotpotJumpUnit unit) {
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();

        int atkRange = config.getModelConfigMap().get(unit.getConfigId()).getAtkRange();
        JumpBoardGrid unitGrid = findBoardGridByJumpGrid(unit.getHeadPos());
        if (unitGrid.distanceTo(mainRoleBordGrid) <= atkRange) {
            return true;
        }

        return false;
    }

    /**
     * 有持续效果的格子减回合,同时更新格子数量
     */
    private void effectGridDecOneRound() {
        List<HotpotJumpGrid> showGrids = new ArrayList<>();
        List<HotpotJumpGrid> resultGrids = new ArrayList<>();
        for (HotpotJumpGrid jumpGrid : effectGridMap.values()) {
            jumpGrid.effectDecOneRound();
            HotpotJumpGrid clone = jumpGrid.clone();
            showGrids.add(clone);

            if (!clone.getEffects().isEmpty()) {
                resultGrids.add(clone);
            }
        }
        gameData.setEffectGrids(resultGrids);

        if (!showGrids.isEmpty()) {
            HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
            show.setGrids(showGrids);
        }
    }

    private void removeEffectGridByEffectType(int effectType) {
        List<HotpotJumpGrid> showGrids = new ArrayList<>();
        List<HotpotJumpGrid> resultGrids = new ArrayList<>();
        for (HotpotJumpGrid effectGrid : effectGridMap.values()) {
            for (List<Integer> effect : effectGrid.getEffects()) {
                int skillId = effect.get(0);
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig == null) {
                    continue;
                }
                if (skillConfig.skillEffect.getEffectType() == effectType) {//更新踩到的DeBuff回合
                    int effectRound = effect.get(1);
                    for (int i = 0; i < effectRound; i++) {
                        effectGrid.effectDecOneRound();
                    }
                    HotpotJumpGrid clone = effectGrid.clone();
                    showGrids.add(clone);
                }
            }

            if (!effectGrid.getEffects().isEmpty()) {
                resultGrids.add(effectGrid);
            }
        }

        if (!showGrids.isEmpty()) {
            gameData.setEffectGrids(resultGrids);

            effectGridMap.clear();
            for (HotpotJumpGrid effectGrid : gameData.getEffectGrids()) {
                JumpBoardGrid boardGrid = findBoardGridByJumpGrid(effectGrid);
                effectGridMap.put(boardGrid, effectGrid);
            }

            HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.EffectChange);
            show.setGrids(showGrids);
        }
    }

    /**
     * 单位身上的效果减回合
     */
    private void unitGridEffectDecOneRound() {
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            boolean needAddShield = false;
            for (List<Integer> effect : unit.getHeadPos().getEffects()) {
                int skillId = effect.get(0);
                int remainRound = effect.get(1);
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig.skillEffect.getEffectType() == eHotpotJumpEffect.Boss4Dizzy.getValue()) {
                    if (remainRound == 1) {
                        needAddShield = true;
                    }
                }
            }
            unit.getHeadPos().effectDecOneRound();

            if (needAddShield) {
                unit.getHeadPos().setShield(1);
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    bodyPo.setShield(1);
                }
                HotpotJumpShowGridChange show2 = createShow(eHotpotJumpShow.EffectChange);
                show2.setUnit(unit);
            }
        }
    }

    /**
     * 最终结算,进入下一回合,还是失败或者通关
     */
    private void roundEnd() {
        showAmount++;
        effectGridDecOneRound();
        unitGridEffectDecOneRound();
        //判断要不要生成BOSS
        checkAndCreateBoss();

        if (isGuide && gameData.getRound() <= 2) {
            List<HotpotJumpUnit> hotpotJumpUnits = config.initGuideEnemyList(this, gameData.getRound() + 1);
            for (HotpotJumpUnit unit : hotpotJumpUnits) {
                unit.setId(gameData.generalUnitUniqueId());
                joinUnit(unit, true);
            }
        } else {
            checkAndCreateNewUnit();
        }

        roundEndSkillDeal();
        unitBeHurtSkillSettle();

        stepChange(eHotpotJumpStep.RoundEnd);
        unitDeadSettle();
        if (!gameData.getSkillIds().isEmpty()) {//等待技能选择
            return;
        }

        addGameScore(config.getHOTPOTJUMP_ROUND_END_ADD_SCORE(), config.getHOTPOTJUMP_ROUND_END_ADD_SCORE());
        gameData.setJumpAmount(0);
        gameData.setRound(gameData.getRound() + 1);
    }

    public List<JumpBoardGrid> calcRangeGrids(JumpBoardGrid grid, HotpotJumpSkillRange skillRange, eJumpDirection direction) {
        List<JumpBoardGrid> result = new ArrayList<>();
        if (skillRange.getRangeType() == eHotpotChooseRangeType.Point.getValue()) {
            result.add(grid);
        } else if (skillRange.getRangeType() == eHotpotChooseRangeType.Line.getValue()) {
            result.addAll(board.findPathGrids(grid, direction, -1, true));//指定方向取一下
            result.addAll(board.findPathGrids(grid, direction.getOppositeDirection(), -1, false));//反向取一下
        } else if (skillRange.getRangeType() == eHotpotChooseRangeType.Circle.getValue()) {
            result.add(grid);
            List<JumpBoardGrid> surroundGrids = board.findSurroundGrids(grid, skillRange.getDistance());
            result.addAll(surroundGrids);
        } else if (skillRange.getRangeType() == eHotpotChooseRangeType.Cross.getValue()) {
            result.add(grid);
            result.addAll(board.findCrossPathGrids(grid, gridDirectionMap.get(grid), skillRange.getDistance()));
        }
        return result;
    }

    /**
     * 重新计算下主角的属性,更新血量
     */
    public void reCalcMainRoleAttr() {
        Map<eHotpotJumpAttr, Integer> attrMap = config.calcMainRoleAttr(gameData.getMainRole());
        gameData.getMainRole().setAttrMap(attrMap);

        Integer attrHp = gameData.getMainRole().getAttrMap().get(eHotpotJumpAttr.Hp);
        int oldHp = gameData.getMainRole().getGrid().getHp();
        int oldHpMax = gameData.getMainRole().getGrid().getHpMax();
        int diffHp = attrHp - oldHpMax;
        if (oldHp > 0) {
            gameData.getMainRole().getGrid().setHp(oldHp + diffHp);
        }
        gameData.getMainRole().getGrid().setHpMax(attrHp);
    }

    public void skillChooseByGuide(int skillId) {
        this.isGuide = true;
        skillChoose(skillId, false, false);
    }

    public void skillChoose(int skillId, boolean isBuySilver, boolean isBuyGold) {
        this.isBuySilver = isBuySilver;
        this.isBuyGold = isBuyGold;
        HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
        if (skillConfig == null) {
            return;
        }
        gameData.setSkillIds(new ArrayList<>());

        HotpotJumpSkillEffect skillEffect = skillConfig.skillEffect;
        if (skillEffect.getEffectType() == eHotpotJumpEffect.Heal.getValue()) {
            if (gameData.getMainRole().getGrid().getHp() < gameData.getMainRole().getGrid().getHpMax()) {
                int healMulti = skillEffect.getValueByLevel(1);
                int healValue = BigDecimal.valueOf(gameData.getMainRole().getGrid().getHpMax())
                        .multiply(BigDecimal.valueOf(healMulti).divide(BigDecimal.valueOf(1000))).setScale(0, BigDecimal.ROUND_UP).intValue();
                gameData.getMainRole().getGrid().setHp(gameData.getMainRole().getGrid().getHp() + healValue);
                if (gameData.getMainRole().getGrid().getHp() > gameData.getMainRole().getGrid().getHpMax()) {
                    gameData.getMainRole().getGrid().setHp(gameData.getMainRole().getGrid().getHpMax());
                }
                HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.BloodSucking);
                show.setMainRole(gameData.getMainRole());
            }
        } else if (skillEffect.getEffectType() == eHotpotJumpEffect.Shield.getValue()) {
            int shieldMulti = skillEffect.getValueByLevel(1);
            int shieldAdd = BigDecimal.valueOf(gameData.getMainRole().getGrid().getHpMax())
                    .multiply(BigDecimal.valueOf(shieldMulti).divide(BigDecimal.valueOf(1000))).setScale(0, BigDecimal.ROUND_UP).intValue();
            gameData.getMainRole().getGrid().setShield(gameData.getMainRole().getGrid().getShield() + shieldAdd);
            if (gameData.getMainRole().getGrid().getShield() > gameData.getMainRole().getGrid().getHpMax()) {
                gameData.getMainRole().getGrid().setShield(gameData.getMainRole().getGrid().getHpMax());
            }
            HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.BloodSucking);
            show.setMainRole(gameData.getMainRole());
        } else {
            gameData.getMainRole().addSkillId(skillId);

            if (skillConfig.getTriggerTiming() == eHotpotSkillTrigger.Forever.getValue()) {
                reCalcMainRoleAttr();
            }
        }

        mainRoleLvUpCheck();

        if (!gameData.getSkillIds().isEmpty()) {
            return;
        }

        if (gameData.getGameStep() == eHotpotJumpStep.JumpEnd.getValue()) {
            //怪开始动
            unitAction();
            unitDeadSettle();
            showAmount++;
            if (!gameData.getSkillIds().isEmpty()) {//等待技能选择
                return;
            }
            //最终结算,进入下一回合,还是失败或者通关
            roundEnd();
        } else if (gameData.getGameStep() == eHotpotJumpStep.UnitAction.getValue()) {
            roundEnd();
        } else if (gameData.getGameStep() == eHotpotJumpStep.RoundEnd.getValue()) {
            addGameScore(config.getHOTPOTJUMP_ROUND_END_ADD_SCORE(), config.getHOTPOTJUMP_ROUND_END_ADD_SCORE());
            gameData.setRound(gameData.getRound() + 1);
        }
    }

    /**
     * 计算敌方单元踩中陷阱的伤害
     *
     * @param unit
     */
    private void dealUnitTriggerTrap(HotpotJumpUnit unit) {
        JumpBoardGrid headGrid = findBoardGridByJumpGrid(unit.getHeadPos());
        HotpotJumpGrid effectJumpGrid = effectGridMap.get(headGrid);
        if (effectJumpGrid != null) {
            int trapDamage = 0;
            int skillId = 0;
            for (List<Integer> effect : effectJumpGrid.getEffects()) {
                skillId = effect.get(0);
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig == null) {
                    continue;
                }

                if (skillConfig.skillEffect.getEffectType() != eHotpotJumpEffect.GridTrapDamage.getValue()) {
                    continue;
                }
                int skillLv = gameData.getMainRole().findSkillLv(skillId);
                int valueByLevel = skillConfig.skillEffect.getValueByLevel(skillLv);
                trapDamage = gameData.getMainRole().calcSkillDamage(valueByLevel, getRoleSkillAddAtkMulti(), config.getJumpAtkMulti(gameData.getJumpAmount()));
                break;
            }
            if (trapDamage > 0) {
                HotpotJumpShowGridChange atkShow = onceAtkUnit(headGrid, trapDamage, false, true);
                if (atkShow != null) {
                    atkShow.setSkillId(skillId);
                }
            }
        }

        //boss的其他位置都要单独算伤害
        for (HotpotJumpGrid bodyPos : unit.getBodyPos()) {
            JumpBoardGrid bodyGrid = findBoardGridByJumpGrid(bodyPos);
            effectJumpGrid = effectGridMap.get(bodyGrid);
            if (effectJumpGrid == null) {
                continue;
            }
            int trapDamage = 0;
            int skillId = 0;
            for (List<Integer> effect : effectJumpGrid.getEffects()) {
                skillId = effect.get(0);
                HotpotJumpSkillConfig skillConfig = config.getSkillConfigMap().get(skillId);
                if (skillConfig == null) {
                    continue;
                }

                if (skillConfig.skillEffect.getEffectType() != eHotpotJumpEffect.GridTrapDamage.getValue()) {
                    continue;
                }
                int skillLv = gameData.getMainRole().findSkillLv(skillId);
                int valueByLevel = skillConfig.skillEffect.getValueByLevel(skillLv);
                trapDamage = gameData.getMainRole().calcSkillDamage(valueByLevel, getRoleSkillAddAtkMulti(), config.getJumpAtkMulti(gameData.getJumpAmount()));
                break;
            }
            if (trapDamage > 0) {
                HotpotJumpShowGridChange atkShow = onceAtkUnit(bodyGrid, trapDamage, false, true);
                if (atkShow != null) {
                    atkShow.setSkillId(skillId);
                }
            }
        }
    }

    /**
     * 从怪物池里取新的怪物
     */
    public void checkAndCreateNewUnit() {
        if (isOnlyCheckUnitAtk) {
            return;
        }
        HotpotJumpNumConfig numConfig = config.getNumConfigByRound(gameData.getRound());
        int minUnitNum = numConfig.getStableNum(); //盘面要求最少小兵数量
        int maxUnitNum = numConfig.getMaxNum(); //盘面最大小兵数量
        int haveNum = 0;
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            if (!config.isBoss(unit.getConfigId())) {
                haveNum++;
            }
        }

        int createNum = 0;
        if (haveNum < minUnitNum) {
            createNum = minUnitNum - haveNum;
        } else if (haveNum < maxUnitNum) {
            createNum = numConfig.getMinNum();
        }
        if (createNum > 0) {
//            normalRandomCreateNewUnits(createNum);
            createNewUnitsByU(createNum);
//            createNewUnitsByRandomMatch(createNum);
        }
    }

    public HotpotJumpUnit createJumpUnit(int configId, int level, int exp, int hpMax, int atk, JumpBoardGrid emptyGrid) {
        HotpotJumpUnit unit = new HotpotJumpUnit();
//        unit.setId(gameData.generalUnitUniqueId());
        unit.setCreateRound(gameData.getRound());
        unit.setConfigId(configId);
        unit.setLevel(level);
        unit.setAtk(atk);
        unit.setExp(exp);

        HotpotJumpGrid jumpGrid = new HotpotJumpGrid(emptyGrid.getX(), emptyGrid.getY());
        jumpGrid.setHpMax(hpMax);
        jumpGrid.setHp(jumpGrid.getHpMax());
        unit.setHeadPos(jumpGrid);
        return unit;
    }

    public String printfBoard() {
        if (!Config.isDebug()) {
            return "";
        }
        String black = "⬢";
        String empty = "⬡";
        String roleStr = "😊";
        String unitStr = "🐻";
        String bossStr = "👹";
        String bossBodyStr = "👿";
        board.resetPrintf(empty);

        for (HotpotJumpUnit unit : gameData.getUnits()) {
            JumpBoardGrid grid = findBoardGridByJumpGrid(unit.getHeadPos());
            if (config.isBoss(unit.getConfigId())) {
                grid.setPrintf(bossStr);
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    JumpBoardGrid bodyGrid = findBoardGridByJumpGrid(bodyPo);
                    bodyGrid.setPrintf(bossBodyStr);
                }
            } else {
                grid.setPrintf(unitStr);
            }
        }

        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        mainRoleBordGrid.setPrintf(roleStr);

        StringBuilder out = new StringBuilder();
        out.append("\n");
        for (int y = 0; y < board.board.length; y++) {
            // 每行前的缩进，模拟偏移以显示六边形结构
            out.append(y % 2 == 0 ? " " : "");
            for (int x = 0; x < board.board.length; x++) {
                out.append((board.board[y][x] == null ? " " : board.board[y][x].getPrintf()) + " ");
            }
            out.append("\n");
        }

//        System.out.println(out);
//        System.out.println("---------------------------");
        logger.info(out);
        return out.toString();
    }

    public void checkAndCreateBoss() {
        if (isOnlyCheckUnitAtk) {
            return;
        }
        int bossIdx = gameData.getBossIdx();
        if (bossIdx < config.getBossRound().size()) {
            List<Integer> bossParams = config.getBossRound().get(bossIdx);
            int bossRound = bossParams.get(0);
            int bossLevel = bossParams.get(1);
            if (gameData.getRound() + 1 >= bossRound) {
                int bossConfigId = gameData.getBossIds().get(bossIdx);

                boolean haveBoss = false;
                for (HotpotJumpUnit unit : gameData.getUnits()) {
                    if (config.isBoss(unit.getConfigId())) {
                        haveBoss = true;
                        break;
                    }
                }
                if (!haveBoss) {
                    gameData.setBossIdx(bossIdx + 1);
                    createAndJoinBoss(bossConfigId, bossLevel);
                }
            }
        }
    }

    public HotpotJumpUnit createAndJoinBoss(int bossConfigId, int bossLevel) {
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        HotpotJumpModelConfig modelConfigById = config.getModelConfigById(bossConfigId);
        if (modelConfigById == null) {
            return null;
        }

        JumpBoardGrid bornGrid = null;
        //找配置的出生点里离主角最远的
        List<List<Integer>> bornPosList = modelConfigById.getBornPosList();
        int offsetIdx = 0;
        for (int i = 0; i < bornPosList.size(); i++) {
            List<Integer> list = bornPosList.get(i);
            int x = list.get(0);
            int y = list.get(1);

            JumpBoardGrid grid = board.findGrid(x, y);
            if (bornGrid == null) {
                bornGrid = grid;
            }

            int compareDistance = bornGrid.distanceTo(mainRoleBordGrid);
            int distance = grid.distanceTo(mainRoleBordGrid);
            if (distance > compareDistance) {
                bornGrid = grid;
                offsetIdx = i;
            }
        }
        HotpotJumpUnit bossUnit = createBoss(bornGrid, modelConfigById, bossLevel, offsetIdx);

        //Boss出生的时候如果有其他小怪,要干掉小怪
        killUnitByBossBody(bossUnit);

        joinUnit(bossUnit, true);
        return bossUnit;
    }

    public HotpotJumpUnit createBoss(JumpBoardGrid bornGrid, HotpotJumpModelConfig modelConfigById, int bossLevel, int offsetIdx) {
        int bossConfigId = modelConfigById.getId();
        List<Integer> attrs = config.calcUnitAtkAndHp(modelConfigById, bossLevel);

        HotpotJumpUnit bossUnit = createJumpUnit(bossConfigId, bossLevel, 0, attrs.get(1), attrs.get(0), bornGrid);
        bossUnit.setId(gameData.generalUnitUniqueId());

        //生成身体部分
        List<HotpotJumpGrid> bodyGrids = new ArrayList<>();
        if (config.isBoss1(bossConfigId)) {//线性的身体
            JumpBoardGrid iterGrid = bornGrid;
            List<List<Integer>> offsetList = modelConfigById.getOffsetList();
            List<Integer> directions = offsetList.get(offsetIdx);
            for (Integer direction : directions) {
                List<Integer> pos = iterGrid.findDirectionNeighborPos(eJumpDirection.getDirection(direction));
                int x = pos.get(0);
                int y = pos.get(1);
                JumpBoardGrid grid = board.findGrid(x, y);
                iterGrid = grid;

                HotpotJumpGrid jumpGrid = new HotpotJumpGrid(grid.getX(), grid.getY());
                bodyGrids.add(jumpGrid);
            }
        } else if (config.isBoss2(bossConfigId)) {//周围一圈
            List<JumpBoardGrid> neighbors = board.getNeighbors(bornGrid);
            for (JumpBoardGrid neighbor : neighbors) {
                HotpotJumpGrid jumpGrid = new HotpotJumpGrid(neighbor.getX(), neighbor.getY());
                bodyGrids.add(jumpGrid);
            }
        } else if (config.isBoss3(bossConfigId)) {
            List<JumpBoardGrid> neighbors = board.getNeighbors(bornGrid);
            for (JumpBoardGrid neighbor : neighbors) {
                HotpotJumpGrid jumpGrid = new HotpotJumpGrid(neighbor.getX(), neighbor.getY());
                bodyGrids.add(jumpGrid);
            }
            bossUnit.getHeadPos().setShield(1);
        } else if (config.isBoss4(bossConfigId)) {//往每个方向距离2的终点
            bossUnit.getHeadPos().setShield(1);
            for (eJumpDirection direction : eJumpDirection.getAllValidDirections()) {
                List<JumpBoardGrid> pathGrids = board.findPathGrids(bornGrid, direction, 2, false);
                JumpBoardGrid grid = pathGrids.get(pathGrids.size() - 1);
                HotpotJumpGrid jumpGrid = new HotpotJumpGrid(grid.getX(), grid.getY());
                //身体加护盾
                jumpGrid.setShield(1);
                bodyGrids.add(jumpGrid);
            }
        }

        bossUnit.setBodyPos(bodyGrids);
        return bossUnit;
    }

    /**
     * 怪物生成时遍历计算每个空点位的μ_n
     * 1.计算an=(a-r1)^2
     * 2.计算bn=(b-r2)^2,每个怪对该点位都有一个b
     * 3.μ_n=an*w1+bn*w2
     * 4.对μ_n从小到大排序获得μ_1、μ_2、μ_3......
     * 5.根据场面稳定数获取所需生成数量，依次填入排序结果
     * W1=当前场面剩余敌人数
     * W2=(stableNUm-W1)/(W1+1)
     *
     * @return
     */
    public List<JumpBoardGrid> calcUEmptyGrids() {
        HotpotJumpNumConfig numConfig = config.getNumConfigByRound(gameData.getRound());
        List<Integer> createPosRuleParams = config.getCreatePosRuleParams(gameData.getRound());
        int r1 = createPosRuleParams.get(1);
        int r2 = createPosRuleParams.get(2);

        List<JumpBoardGrid> emptyGrids = new ArrayList<>();
        Map<JumpBoardGrid, BigDecimal> sortValueMap = new HashMap<>();
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        for (JumpBoardGrid[] grids : board.board) {
            for (JumpBoardGrid grid : grids) {
                if (grid == null) {
                    continue;
                }
                if (mainRoleBordGrid == grid) {
                    continue;
                }
                HotpotJumpUnit unitByGrid = findUnitByGrid(grid);
                if (unitByGrid != null) {
                    continue;
                }

                emptyGrids.add(grid);

                BigDecimal a = BigDecimal.valueOf(grid.distanceTo(mainRoleBordGrid) - r1);
                a = a.multiply(a);
                BigDecimal totalB = BigDecimal.ZERO;
                for (HotpotJumpUnit unit : gameData.getUnits()) {
//                    if (config.isBoss(unit.getConfigId())) {
//                        continue;
//                    }
                    JumpBoardGrid unitGrid = findBoardGridByJumpGrid(unit.getHeadPos());
                    BigDecimal b = BigDecimal.valueOf(grid.distanceTo(unitGrid) - r2);
                    b = b.multiply(b);
                    totalB = totalB.add(b);
                }
                BigDecimal w1 = BigDecimal.valueOf(unitMap.size());
                BigDecimal w2 = BigDecimal.valueOf(numConfig.getStableNum() - w1.intValue())
                        .divide(w1.add(BigDecimal.ONE), 8, RoundingMode.DOWN);
//                BigDecimal w2 = w1.divide(BigDecimal.valueOf(numConfig.getStableNum() - numConfig.getMinNum()), 8, RoundingMode.DOWN);


                BigDecimal u = a.multiply(w1).add(totalB.multiply(w2));
                sortValueMap.put(grid, u);
            }
        }

        emptyGrids.sort((o1, o2) -> sortValueMap.get(o1).compareTo(sortValueMap.get(o2)));

//        for (int i = 0; i < emptyGrids.size() ; i++) {
//            JumpBoardGrid emptyGrid = emptyGrids.get(i);
//            System.out.println("打印排序后的坐标" + emptyGrid.getX() + ":" + emptyGrid.getY() + "=" + sortValueMap.get(emptyGrid));
//        }

        return emptyGrids;
    }

    /**
     * 随机获得空格,排除主角周边excludeDistance距离的格子
     *
     * @param excludeDistance
     * @return
     */
    public List<JumpBoardGrid> findEmptyGrids(int excludeDistance) {
        List<JumpBoardGrid> emptyGrids = new ArrayList<>();
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        for (JumpBoardGrid[] grids : board.board) {
            for (JumpBoardGrid grid : grids) {
                if (grid == null) {
                    continue;
                }
                HotpotJumpUnit unitByGrid = findUnitByGrid(grid);
                if (unitByGrid != null) {
                    continue;
                }

                if (grid.distanceTo(mainRoleBordGrid) <= excludeDistance) {
                    continue;
                }

                emptyGrids.add(grid);
            }
        }
        return emptyGrids;
    }

    /**
     * 全随机的方式生成
     *
     * @param createNum
     */
    public void normalRandomCreateNewUnits(int createNum) {
        List<List<Integer>> unitCreateParams = takeUnitCreateParamsFromPool(createNum);
        List<JumpBoardGrid> emptyGrids = findEmptyGrids(1);
        Collections.shuffle(emptyGrids);

        for (int i = 0; i < createNum; i++) {
            int emptyIdx = i;
            JumpBoardGrid emptyGrid = emptyGrids.get(emptyIdx);
            HotpotJumpUnit unitByGrid = findUnitByGrid(emptyGrid);
            if (unitByGrid != null) {
                i--;
                continue;
            }

            List<Integer> params = unitCreateParams.get(i);
            int configId = params.get(0);
            int level = params.get(1);
            int exp = params.get(2);

            HotpotJumpModelConfig modelConfigById = config.getModelConfigById(configId);
            if (modelConfigById == null) {
                continue;
            }

            List<Integer> attrs = config.calcUnitAtkAndHp(modelConfigById, level);

            HotpotJumpUnit unit = createJumpUnit(configId, level, exp, attrs.get(1), attrs.get(0), emptyGrid);
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }
    }

    /**
     * 按公式算u值生成
     */
    public void createNewUnitsByU(int createNum) {
        List<List<Integer>> unitCreateParams = takeUnitCreateParamsFromPool(createNum);
        //遍历主角两圈外的空格
        List<JumpBoardGrid> emptyGrids = calcUEmptyGrids();

        int bossGridNum = 0;
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            if (config.isBoss(unit.getConfigId())) {
                bossGridNum = 1 + unit.getBodyPos().size();
                break;
            }
        }
        //计算m=(场面空点总数-boss占点数)/k(向下取整)
        int m = (emptyGrids.size() - bossGridNum) / createNum;

        int emptyIdx = 0;
        for (int i = 0; i < createNum; i++) {
            JumpBoardGrid emptyGrid = emptyGrids.get(emptyIdx);
            emptyIdx += m;
            HotpotJumpUnit unitByGrid = findUnitByGrid(emptyGrid);
            if (unitByGrid != null) {
                i--;
                continue;
            }

            List<Integer> params = unitCreateParams.get(i);
            int configId = params.get(0);
            int level = params.get(1);
            int exp = params.get(2);

            HotpotJumpModelConfig modelConfigById = config.getModelConfigById(configId);
            if (modelConfigById == null) {
                continue;
            }

            List<Integer> attrs = config.calcUnitAtkAndHp(modelConfigById, level);

            HotpotJumpUnit unit = createJumpUnit(configId, level, exp, attrs.get(1), attrs.get(0), emptyGrid);
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }
    }

    /**
     * 通过多次随机,取匹配度最高的生成
     *
     * @param createNum
     */
    public void createNewUnitsByRandomMatch(int createNum) {
        List<List<Integer>> unitCreateParams = takeUnitCreateParamsFromPool(createNum);
        List<JumpBoardGrid> emptyGrids = new ArrayList<>();
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        for (JumpBoardGrid[] grids : board.board) {
            for (JumpBoardGrid grid : grids) {
                if (grid == null) {
                    continue;
                }
                HotpotJumpUnit unitByGrid = findUnitByGrid(grid);
                if (unitByGrid != null) {
                    continue;
                }

                if (grid.distanceTo(mainRoleBordGrid) <= 1) {
                    continue;
                }

                emptyGrids.add(grid);
            }
        }
        int minDiff1 = 9999;
        int minDiff2 = 9999;
        int resultK = 0;

        int r1 = 10;
        int r2 = 2;

        Map<Integer, List<HotpotJumpUnit>> resultCreateMap = new HashMap<>();
        for (int k = 0; k < 100; k++) {
            Collections.shuffle(emptyGrids);

            List<HotpotJumpUnit> units = new ArrayList<>(gameData.getUnits());
            List<HotpotJumpUnit> createUnits = new ArrayList<>();
            List<JumpBoardGrid> chooseGrids = emptyGrids.subList(0, createNum);
            for (int i = 0; i < chooseGrids.size(); i++) {
                JumpBoardGrid chooseGrid = chooseGrids.get(i);
                List<Integer> params = unitCreateParams.get(i);
                int configId = params.get(0);
                int level = params.get(1);
                int exp = params.get(2);
                HotpotJumpModelConfig modelConfigById = config.getModelConfigById(configId);
                if (modelConfigById == null) {
                    continue;
                }
                List<Integer> attrs = config.calcUnitAtkAndHp(modelConfigById, level);
                HotpotJumpUnit jumpUnit = createJumpUnit(configId, level, exp, attrs.get(1), attrs.get(0), chooseGrid);
                units.add(jumpUnit);

                createUnits.add(jumpUnit);
            }

            Map<JumpBoardGrid, HotpotJumpUnit> tempUnitMap = new HashMap<>();
            for (HotpotJumpUnit unit : units) {
                JumpBoardGrid boardGrid = findBoardGridByJumpGrid(unit.getHeadPos());
                tempUnitMap.put(boardGrid, unit);
                for (HotpotJumpGrid bodyPo : unit.getBodyPos()) {
                    tempUnitMap.put(findBoardGridByJumpGrid(bodyPo), unit);
                }
            }

            resultCreateMap.put(k, createUnits);

            List<Integer> list = calcUnitMatchValues(tempUnitMap);
            Integer canMoveAmount = list.get(0);
            Integer enemyAmount = list.get(1);

            int diff1 = Math.abs(canMoveAmount - r1);
            int diff2 = Math.abs(enemyAmount - r2);
            if (diff1 < minDiff1) {
                minDiff1 = diff1;
                minDiff2 = diff2;
                resultK = k;
            } else if (diff1 == minDiff1) {
                if (canMoveAmount > r1) {
                    minDiff1 = diff1;
                    minDiff2 = diff2;
                    resultK = k;
                } else {
                    if (diff2 < minDiff2) {
                        minDiff1 = diff1;
                        minDiff2 = diff2;
                        resultK = k;
                    } else if (diff2 == minDiff2) {
                        if (enemyAmount < r2) {
                            minDiff1 = diff1;
                            minDiff2 = diff2;
                            resultK = k;
                        }
                    }
                }
            }
        }

        List<HotpotJumpUnit> createUnits = resultCreateMap.get(resultK);
        for (HotpotJumpUnit unit : createUnits) {
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }
    }

    /**
     * 计算主角和当前盘面的怪的移动通路数和敌人耦合度
     * 移动通路指玩家可以跳跃的
     *
     * @param unitMap
     * @return
     */
    public List<Integer> calcUnitMatchValues(Map<JumpBoardGrid, HotpotJumpUnit> unitMap) {
        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        List<JumpBoardGrid> neighbors = board.getNeighbors(mainRoleBordGrid);
        int canMoveAmount = 0;
        int enemyAmount = 0;
        for (JumpBoardGrid neighbor : neighbors) {
            if (!unitMap.containsKey(neighbor)) {
                canMoveAmount++;
            }
        }

        for (Map.Entry<JumpBoardGrid, HotpotJumpUnit> entry : unitMap.entrySet()) {
            JumpBoardGrid enemyGrid = entry.getKey();

            List<JumpBoardGrid> enemyNeighbors = board.getNeighbors(enemyGrid);
            for (JumpBoardGrid enemyNeighbor : enemyNeighbors) {
                if (unitMap.containsKey(enemyNeighbor)) {
                    enemyAmount++;
                }
            }

            eJumpDirection direction = mainRoleBordGrid.calcTargetDirection(enemyGrid);
            if (direction == eJumpDirection.None) {
                continue;
            }
            int distance = enemyGrid.distanceTo(mainRoleBordGrid);
            List<JumpBoardGrid> crossGrids = board.findPathGrids(mainRoleBordGrid, direction, distance * 2, false);
            if (crossGrids.size() != distance * 2) {
                continue;
            }
            boolean canJump = true;
            for (JumpBoardGrid crossGrid : crossGrids) {
                if (crossGrid != enemyGrid && unitMap.containsKey(crossGrid)) {
                    canJump = false;
                    break;
                }
            }
            if (canJump) {
                canMoveAmount++;
            }
        }

        return Arrays.asList(canMoveAmount, enemyAmount);
    }

    /**
     * 从池子中随机取怪,这个方法会改变池子的内容
     *
     * @param createNum
     * @return
     */
    public List<List<Integer>> takeUnitCreateParamsFromPool(int createNum) {
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0; i < createNum; i++) {
            int unitPoolId = gameData.getUnitPoolId();
            HotpotJumpMissionConfig missionConfig = config.getMissionConfig(unitPoolId);
            if (missionConfig == null) {
                continue;
            }

            List<List<Integer>> unitPoolRemain = gameData.getUnitPoolRemain();
            int idx = randomHelper.next(unitPoolRemain.size());
            List<Integer> unitParams = unitPoolRemain.get(idx);
            Integer configId = unitParams.get(0);
            Integer remainNum = unitParams.get(1);
            Integer exp = unitParams.get(2);
            HotpotJumpModelConfig modelConfigById = config.getModelConfigById(configId);
            if (modelConfigById == null) {
                continue;
            }

            result.add(Arrays.asList(configId, missionConfig.getLevel(), exp));

            if (remainNum == 1) {
                unitPoolRemain.remove(idx);

                if (unitPoolRemain.isEmpty()) {
                    HotpotJumpMissionConfig nextPool = config.getNextMissionConfig(unitPoolId);
                    gameData.setUnitPoolId(nextPool.getId());
                    gameData.setUnitPoolRemain(config.getUnionPool(nextPool));
                }
            } else {
                unitPoolRemain.get(idx).set(1, remainNum - 1);
            }
        }
        return result;
    }

    public void revive(boolean isBuySilver, boolean isBuyGold) {
        this.isBuySilver = isBuySilver;
        this.isBuyGold = isBuyGold;
        int reviveHpRate = config.getReviveHpRate();
        int hpMax = gameData.getMainRole().getGrid().getHpMax();
        int reviveHp = BigDecimal.valueOf(hpMax).multiply(BigDecimal.valueOf(reviveHpRate).divide(BigDecimal.valueOf(1000))).setScale(0, BigDecimal.ROUND_UP).intValue();
        if (reviveHp > hpMax) {
            reviveHp = hpMax;
        }
        gameData.getMainRole().getGrid().setHp(reviveHp);
        gameData.getMainRole().getGrid().setEffects(new ArrayList<>());
        gameData.setReviveTimes(gameData.getReviveTimes() + 1);

        HotpotJumpShowGridChange show = createShow(eHotpotJumpShow.Revive);
        show.setMainRole(gameData.getMainRole());

        if (gameData.getGameStep() == eHotpotJumpStep.JumpEnd.getValue()) {
            //怪开始动
            unitAction();
            unitDeadSettle();
            showAmount++;
            if (!gameData.getSkillIds().isEmpty()) {//等待技能选择
                return;
            }

            roundEnd();
        } else if (gameData.getGameStep() == eHotpotJumpStep.UnitAction.getValue()) {
            roundEnd();
        } else if (gameData.getGameStep() == eHotpotJumpStep.RoundEnd.getValue()) {
            addGameScore(config.getHOTPOTJUMP_ROUND_END_ADD_SCORE(), config.getHOTPOTJUMP_ROUND_END_ADD_SCORE());
            gameData.setRound(gameData.getRound() + 1);
        }
    }

    public void initGameByStr(String strIn) {
        List<List<Integer>> posList = new ArrayList<>();
        for (String str : strIn.split("\\|")) {
            List<Integer> list = StringUtils.stringToIntegerList(str, ",");
            posList.add(list);
        }

        List<Integer> mainRolePos = posList.get(0);

        this.gameData = new UserHotpotJumpGameData();
        gameData.setRound(1);
        gameData.setScore(0);
        gameData.setMaxUnitId(1);
        gameData.setPotId(config.randomPotId());
        HotpotJumpMainRole mainRole = config.initMainRole();
        mainRole.getGrid().setX(mainRolePos.get(0));
        mainRole.getGrid().setY(mainRolePos.get(1));
        gameData.setMainRole(mainRole);

        //随机一个BOSS的出现顺序
        gameData.setBossIds(config.randomBossSort());

        HotpotJumpMissionConfig missionConfig = config.getFirstMissionConfig();
        if (missionConfig != null) {
            gameData.setUnitPoolId(1);
            gameData.setUnitPoolRemain(config.getUnionPool(missionConfig));
        }

        //初始小怪
        for (int i = 1; i < posList.size(); i++) {
            List<Integer> list = posList.get(i);
            int x = list.get(0);
            int y = list.get(1);

            Integer modelId = 1;
            int rewardExp = 0;

            HotpotJumpModelConfig modelConfig = config.getModelConfigById(modelId);
            if (modelConfig == null) {
                continue;
            }

            JumpBoardGrid emptyGrid = board.findGrid(x, y);

            List<Integer> attrs = config.calcUnitAtkAndHp(modelConfig, 1);

            HotpotJumpUnit unit = createJumpUnit(modelId, 1, rewardExp, attrs.get(1), attrs.get(0), emptyGrid);
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }
    }

    public int resetRoleGrid(HotpotJumpProto.HotpotJumpGridTemp gridTemp) {
        int x = gridTemp.getX();
        int y = gridTemp.getY();
        JumpBoardGrid grid = board.findGrid(x, y);
        if (grid == null) {
            return 1;
        }

        HotpotJumpUnit unitByGrid = findUnitByGrid(grid);
        if (unitByGrid != null) {
            return 2;
        }

        JumpBoardGrid mainRoleBordGrid = getMainRoleBordGrid();
        for (eJumpDirection direction : eJumpDirection.getAllValidDirections()) {
            List<JumpBoardGrid> pathGrids = board.findPathGrids(mainRoleBordGrid, direction, 2, false);
            for (JumpBoardGrid pathGrid : pathGrids) {
                HotpotJumpUnit unit = findUnitByGrid(pathGrid);
                if (unit == null) {//还有可以移动的
                    return 3;
                }
            }
        }

        gameData.getMainRole().getGrid().setX(x);
        gameData.getMainRole().getGrid().setY(y);

        return 0;
    }

    /**
     * 练习模式数据
     *
     * @return
     */
    public UserHotpotJumpGameData initGuideGame() {
        this.gameData = new UserHotpotJumpGameData();
        gameData.setRound(1);
        gameData.setScore(0);
        gameData.setMaxUnitId(1);
        gameData.setPotId(config.randomPotId());
        gameData.setMainRole(config.initMainRole());

        //初始小怪
        for (HotpotJumpUnit unit : config.initGuideEnemyList(this, 1)) {
            unit.setId(gameData.generalUnitUniqueId());
            joinUnit(unit, true);
        }

        HotpotJumpMissionConfig missionConfig = config.getFirstMissionConfig();
        if (missionConfig != null) {
            gameData.setUnitPoolId(1);
            gameData.setUnitPoolRemain(config.getUnionPool(missionConfig));
        }

        return gameData;
    }

    public LogHotpotJumpJumpMove parseMoveLog(long userId, int totalTimes) {
        String jumpPos = gameData.getMainRole().getGrid().getX() + "," + gameData.getMainRole().getGrid().getY();
        List<String> roleSkill = new ArrayList<>();
        for (List<Integer> skill : gameData.getMainRole().getSkills()) {
            String skillStr = skill.get(0) + "=" + skill.get(1);
            roleSkill.add(skillStr);
        }
        LogHotpotJumpJumpMove log = new LogHotpotJumpJumpMove(config.getActivityId(), userId, totalTimes,
                gameData.getRound(), gameData.getPotId(), jumpPos, this.pathUnitGrids.size(),
                gameData.getMainRole().getLv(), roleSkill, killIds, totalDamage, totalBeHurt,
                gameData.getMainRole().getGrid().getHp(), gameData.getMainRole().getGrid().getShield(), totalScoreAdd, totalExpAdd);
        return log;
    }

    private List<JumpBoardGrid> answerList = new ArrayList<>();
    private List<JumpBoardGrid> nowJumpList = new ArrayList<>();
    private Map<String, Integer> dfsVisit = new HashMap<>();

    /**
     * 计算推荐跳跃点,跳跃数最多的路径,使用DFS遍历
     *
     * @param startX
     * @param startY
     * @return
     */
    public List<JumpBoardGrid> calcRecommendPath(int startX, int startY) {
        List<JumpBoardGrid> result = new ArrayList<>();
        String black = "⬢";
        String empty = "⬡";

        printfBoard();

        board.resetPrintf(empty);

        JumpBoardGrid startGrid = board.findGrid(startX, startY);
        this.nowJumpList.add(startGrid);
        if (dfsSolve(0)) {
            for (JumpBoardGrid jumpBoardGrid : this.nowJumpList) {
                jumpBoardGrid.setPrintf(black);
            }
        }
        board.printBoard();

        return result;
    }

    /**
     * 找到起点对应单位能跳的点
     *
     * @param startGrid
     * @param targetUnit
     * @return
     */
    private JumpBoardGrid findCanJumpBoardGrid(JumpBoardGrid startGrid, HotpotJumpUnit targetUnit) {
        eJumpDirection findDirection = eJumpDirection.None;
        if (config.isBoss3(targetUnit.getConfigId())) {
            JumpBoardGrid headBoardGrid = findBoardGridByJumpGrid(targetUnit.getHeadPos());
            if (startGrid.calcTargetDirection(headBoardGrid) == eJumpDirection.None) {
                for (HotpotJumpGrid bodyPo : targetUnit.getBodyPos()) {
                    JumpBoardGrid bodyBoardGrid = findBoardGridByJumpGrid(bodyPo);
                    if (startGrid.calcTargetDirection(bodyBoardGrid) != eJumpDirection.None) {
                        findDirection = startGrid.calcTargetDirection(bodyBoardGrid);
                        break;
                    }
                }
            } else {
                findDirection = startGrid.calcTargetDirection(headBoardGrid);
            }
        } else {
            JumpBoardGrid unitBoardGrid = findBoardGridByJumpGrid(targetUnit.getHeadPos());
            if (startGrid.calcTargetDirection(unitBoardGrid) == eJumpDirection.None) {
                return null;
            }
            findDirection = startGrid.calcTargetDirection(unitBoardGrid);
        }

        if (findDirection == eJumpDirection.None) {//不在直线上
            return null;
        }

        List<Integer> pos = startGrid.findDirectionNeighborPos(findDirection);
        JumpBoardGrid iterGrid = board.findGrid(pos.get(0), pos.get(1));
        int distance1 = 0;
        while (iterGrid != null) {
            distance1++;
            HotpotJumpUnit unitByGrid = findUnitByGrid(iterGrid);
            if (unitByGrid != null) {
                if (unitByGrid != targetUnit) {//找到的第一个单位不是目标单位,不能跳
                    return null;
                }

                //遍历到目标了,往目标后面找distance1
                for (int i = 0; i < distance1; i++) {
                    List<Integer> nextPos = iterGrid.findDirectionNeighborPos(findDirection);
                    JumpBoardGrid nextGrid = board.findGrid(nextPos.get(0), nextPos.get(1));
                    if (nextGrid == null) {//找不到盘面肯定不能跳
                        return null;
                    }
                    iterGrid = nextGrid;
                    HotpotJumpUnit nextUnit = findUnitByGrid(iterGrid);
                    if (nextUnit != null) {//boss3的身体要合并算距离
                        if (nextUnit == targetUnit && config.isBoss3(nextUnit.getConfigId())) {
                            i--;
                            continue;
                        } else {//找到了不是BOSS3的其他单位,不能跳
                            return null;
                        }
                    }
                }
                break;
            } else {
                List<Integer> nextPos = iterGrid.findDirectionNeighborPos(findDirection);
                JumpBoardGrid nextGrid = board.findGrid(nextPos.get(0), nextPos.get(1));
                iterGrid = nextGrid;
            }
        }

        if (iterGrid != null) {//判断一下不能跳重复的线段
            for (int i = 0; i < this.nowJumpList.size(); i++) {
                JumpBoardGrid jumpBoardGrid = this.nowJumpList.get(i);
                if (jumpBoardGrid == startGrid) {//找到起点的前后两个点,如果和找到的点一样不能跳
                    if (i > 0) {
                        JumpBoardGrid beforeJump = this.nowJumpList.get(i - 1);
                        if (beforeJump == iterGrid) {
                            iterGrid = null;
                            break;
                        }
                    }
                    if (i < this.nowJumpList.size() - 1) {
                        JumpBoardGrid afterJump = this.nowJumpList.get(i + 1);
                        if (afterJump == iterGrid) {
                            iterGrid = null;
                            break;
                        }
                    }
                }
            }

        }
        return iterGrid;
    }

    public boolean dfsSolve(int jumpAmount) {
        String visitKey = parseVisitKey();
        if (this.dfsVisit.containsKey(visitKey)) return false;
        dfsVisit.put(visitKey, 1);
        if (jumpAmount > 20) {
            return true;
        }
        JumpBoardGrid nowGrid = nowJumpList.get(nowJumpList.size() - 1);
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            JumpBoardGrid nextGrid = findCanJumpBoardGrid(nowGrid, unit);
            if (nextGrid == null) {
                continue;
            }
            dfsMove(nextGrid);
            if (dfsSolve(jumpAmount + 1)) {
                return true;
            }
            dfsMoveBack();
        }
        return false;
    }

    private String parseVisitKey() {
        String key = "";
        for (JumpBoardGrid boardGrid : nowJumpList) {
            key += boardGrid.getX() + "," + boardGrid.getY() + "->";
        }
        return key;
    }

    public boolean isSolveEnd() {
        if (nowJumpList.isEmpty()) {
            return true;
        }
        JumpBoardGrid lastJumpGrid = nowJumpList.get(nowJumpList.size() - 1);

        boolean isEnd = true;
        for (HotpotJumpUnit unit : gameData.getUnits()) {
            JumpBoardGrid canJumpBoardGrid = findCanJumpBoardGrid(lastJumpGrid, unit);
            if (canJumpBoardGrid != null) {
                isEnd = false;
                break;
            }
        }
        return isEnd;
    }

    public void dfsMove(JumpBoardGrid target) {
        this.nowJumpList.add(target);
    }

    public void dfsMoveBack() {
        this.nowJumpList.remove(this.nowJumpList.size() - 1);
    }

    public List<HotpotJumpProto.HotpotJumpCanAtkUnitTemp> parseCanAtkUnitTempList() {
        List<HotpotJumpProto.HotpotJumpCanAtkUnitTemp> resultList = new ArrayList<>();
        if (unitAtkMainRoleRecordMap.isEmpty()) {
            return resultList;
        }

        for (Map.Entry<HotpotJumpUnit, Set<HotpotJumpGrid>> entry : unitAtkMainRoleRecordMap.entrySet()) {
            HotpotJumpProto.HotpotJumpCanAtkUnitTemp.Builder builder = HotpotJumpProto.HotpotJumpCanAtkUnitTemp.newBuilder();
            HotpotJumpUnit unit = entry.getKey();
            builder.setUnit(HotpotJumpPb.parseUnitBuilder(unit));
            for (HotpotJumpGrid jumpGrid : entry.getValue()) {
                builder.addGrid(HotpotJumpPb.parseGridBuilder(jumpGrid));
            }

            resultList.add(builder.build());
        }

        return resultList;
    }
}